Làm cách nào để xóa các tệp được đánh số trong một phạm vi nhất định?


16

Tôi có folderAmột số tập tin với một chuỗi số bắt đầu bằng a_000000. Những gì tôi muốn làm là xóa các tệp bắt đầu từ một số cụ thể: giả sử a_000750cho đến khi kết thúc các tệp trong này folderA. Bất cứ ai có thể xin vui lòng tư vấn làm thế nào để làm điều này bằng cách sử dụng shell script?


Tôi có thể cho rằng tất cả các tên tệp đó có hậu tố 6 chữ số không?
muru

đúng vậy :) họ bắt đầu từ a_000000 cho đến một số nào đó
Tak

5
rm a_000[89]* a_0007[5-9]*?
Rinzwind

@Rinzwind bạn có thể vui lòng giải thích lệnh này?
Tak

2
@ user1460166 a_000[89]*bao gồm mọi tệp bắt đầu bằng a_0008hoặc a_0009, và a_0007[5-9]*bao gồm mọi tệp bắt đầu bằng a_0007và sau đó chứa một số từ 5 đến 9, sau đó là bất cứ thứ gì.
muru

Câu trả lời:


35

Giả sử bạn biết hoặc có thể đoán kết thúc của phạm vi, bạn có thể sử dụng mở rộng cú đúp :

rm a_{000750..000850}

Ở trên sẽ xóa 101 tệp trong phạm vi bao gồm a_000750 và a_000850 (và khiếu nại về tên tệp liên quan đến các tệp không tồn tại). Nếu bạn có quá nhiều tệp cho điều đó, hãy sử dụng find:

find . -name 'a_*' | while read file; do 
  [ "${file#./a_}" -gt 000749 ] && rm -v "$file" 
done

Ở đây, findchỉ đơn giản là liệt kê tất cả các tập tin phù hợp a_*. Danh sách được chuyển đến một whilevòng lặp trong đó mỗi tên tệp được đọc vào biến $file. Sau đó, bằng cách sử dụng các tính năng thao tác chuỗi của bash , nếu phần số (tìm tệp in dưới dạng ./file, do đó chỉ ${file#./a_}in số) 000750hoặc lớn hơn, tệp sẽ bị xóa. Đây -vchỉ là ở đó để bạn có thể xem những gì các tập tin đã được gỡ bỏ.

Lưu ý rằng ở trên giả định tên tập tin lành mạnh. Nếu tên của bạn có thể có khoảng trắng, dòng mới hoặc các ký tự lạ khác, hãy sử dụng tên này thay thế:

find . -name 'a_*' -print0 | while IFS= read -rd '' file; do 
  [ "${file#./a_}" -gt 000749 ] && rm -v "$file" 
done

Tại sao phải tránh [[?
muru

1
@muru tại sao lại dùng nó? [[không đơn giản hóa mọi thứ ở đây [[ "${file#./a_}" > 000749 ]]chẳng hạn, thậm chí không làm cho nó ngắn hơn. Tôi không thích sử dụng cú pháp không cần thiết và cái này thậm chí sẽ hoạt động trong các shell đơn giản hơn như dash.
terdon

Bởi vì [[xử lý không gian và sự kỳ lạ tốt hơn (tôi cũng không quan tâm lắm >).
muru

1
@muru có, nhưng [sẽ ổn nếu bạn trích dẫn biến như tôi có, hoạt động trên nhiều shell hơn và đơn giản hơn.
terdon

Nếu bạn cứ khăng khăng. Không phải vấn đề của tôi.
muru

3

Bạn có thể làm một cái gì đó như thế này:

find . -regextype posix-extended -iregex './a_[0-9]{6}' -execdir bash -c '[[ ${1##./a_} > 000750 ]] && echo $1' "removing: " {} \;

Hoặc là:

find . -regextype posix-extended -iregex './a_[0-9]{6}' | sort | sed '0,/000750/d' | xargs echo

Phương thức đầu tiên giả định một tiền tố cố định, loại bỏ nó và kiểm tra giá trị.

Phương thức thứ hai giả định hậu tố có độ dài cố định (và tiền tố cố định chung) và dựa vào thực tế đó; và rằng, trong khi 201đến trước 31trong từ vựng, nó không trước 031.

Kiểm tra điều này bằng echolệnh và một khi bạn chắc chắn rằng nó liệt kê các tệp chính xác, rmthay vào đó hãy sử dụng .


không ai trong số họ đang làm việc: /
Tak

@ user1460166 ah, đó có thể là do kết hợp regex. Tôi sẽ cập nhật nó.
muru

vẫn không làm việc. btw, các tập tin là .png :)
Tak

@ user1460166 bạn có thể nói nó hoạt động như thế nào không?
muru

Tôi mở terminal, cd vào thư mục sau đó sao chép dòng của bạn và dán nó, nhưng các tệp không bị xóa
Tak

0

Giải pháp vỏ POSIX

Giải pháp đầu tiên của terdon dựa vào việc mở rộng niềng răng , vốn là một đặc tính của bashksh, tuy nhiên, nó không thể được sử dụng trong hệ /bin/shvỏ tiêu chuẩn , mà trên Ubuntu được liên kết với nhau /bin/dash.

Trong trường hợp bạn phải dựa /bin/shvào tính di động của tập lệnh, thường có hai cách để tiếp cận điều này. Một sẽ được thông qua Globing. Chỉ cd folderAvà từ đó chạy rm a_*. Một cách khác, sẽ là triển khai kiểu chữ C để thay thế vòng lặp bằng while <CONDITION>;do ...donengôn ngữ shell và định dạng các số với printf:

$ sh -c 'i=0;while [ $i -le 750 ]; do filename=$(printf "a_%06d" $i);echo "$filename";i=$((i+1)) ;done'

Lưu ý rằng ở đây tôi sử dụng echo. Thay thế echo "$filename"bằng rm ./"$filename"hoặc rm -- "$filename"khi bạn đã sẵn sàng để xóa các tập tin. Cũng lưu ý rằng điều này nên được thực hiện khi bạn đã cded vào thư mục mong muốn.

(ab) sử dụng awk

Awk là một ngôn ngữ giống như C có thể giúp chúng ta theo hai cách: (1) chúng ta có thể tạo tên tệp bằng vòng lặp for và định dạng chúng thông qua sprintfchức năng, và (2) xóa các tệp đã nói thông qua system()lệnh, sẽ chuyển tên tệp và rmlệnh được tạo của chúng ta để /bin/sh:

awk 'BEGIN{for(i=0;i<=750;i++){filename=sprintf("a_%06d",i);system("rm "filename);} }'

Perl

Tiếp tục với ý tưởng về cách tiếp cận di động nơi chúng tôi "tạo" tên tệp, chúng tôi có thể làm tương tự trong Perl:

perl -le 'for(0..750){$fd=sprintf("a_%06d",$_);unlink($fd)}'

0

Đơn giản như

rm partialfilename* -f

Trong ví dụ của bạn, nó là

rm a_00075* -f

1
Rất tiếc phải nói, nhưng đó không phải là một phạm vi, đó là tất cả các tệp bắt đầu bằng a_00075...
Fabby

1
* là ký tự đại diện, OP đang tìm câu trả lời về cách xóa RANGE của mọi thứ ... ví dụ: nếu bạn có tệp từ 1 đến 100 và muốn xóa # 41 đến # 75
Joshua Besneatte
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.