Pertanyaan Bagaimana saya bisa menghapus file bernomor dalam rentang yang diberikan?


saya sudah folderA yang memiliki beberapa file dengan urutan angka dimulai dengan a_000000. Yang ingin saya lakukan adalah menghapus file mulai dari nomor tertentu: katakanlah a_000750 sampai akhir file dalam ini folderA. Adakah yang bisa menyarankan bagaimana melakukan ini menggunakan skrip shell?


11
2017-09-27 14:22


asal


Dapatkah saya berasumsi bahwa semua nama file tersebut memiliki 6-digit akhiran? - muru
ya mereka :) mereka mulai dari a_000000 hingga beberapa angka - Tak
rm a_000[89]* a_0007[5-9]*? - Rinzwind
@Rinzwind bisakah Anda menjelaskan perintah ini? - Tak
@ user1460166 a_000[89]* termasuk setiap file yang diawali dengan a_0008 atau a_0009, dan a_0007[5-9]* termasuk setiap file yang diawali dengan a_0007 dan kemudian berisi angka antara 5 dan 9, diikuti oleh apa pun. - muru


Jawaban:


Dengan asumsi Anda tahu atau dapat menebak ujung kisaran, Anda bisa menggunakannya brace ekspansi:

rm a_{000750..000850}

Di atas akan menghapus 101 file antara a_000750 dan a_000850 inklusif (dan mengeluh tentang nama file yang merujuk ke file yang tidak ada). Jika Anda memiliki terlalu banyak file untuk itu, gunakan find:

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

Di sini, the find cukup daftar semua file yang cocok a_*. Daftar diteruskan ke a while lingkaran di mana setiap nama file dibaca ke dalam variabel $file. Kemudian, menggunakan bash manipulasi string fitur, jika bagian numerik (menemukan file cetakan sebagai ./file, jadi ${file#./a_} hanya cetak nomornya) 000750 atau lebih besar, file dihapus. Itu -v ada di sana sehingga Anda dapat melihat file apa yang dihapus.

Perhatikan bahwa di atas mengasumsikan nama file yang waras. Jika nama Anda dapat memiliki spasi, baris baru, atau karakter aneh lainnya, gunakan ini sebagai gantinya:

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

24
2017-09-27 15:00



Kenapa dihindari [[? - muru
@muru mengapa menggunakannya? [[ tidak menyederhanakan hal-hal di sini [[ "${file#./a_}" > 000749 ]] misalnya, bahkan tidak membuatnya lebih pendek. Saya tidak suka menggunakan sintaks yang tidak perlu dan yang satu ini bahkan akan bekerja dalam cangkang yang lebih sederhana dash. - terdon♦
Karena [[ menangani ruang dan keanehan yang lebih baik (saya tidak terlalu peduli > antara). - muru
@muru ya, tapi [ baik-baik saja jika Anda mengutip variabel seperti yang saya miliki, bekerja pada cangkang yang jauh lebih banyak dan lebih sederhana. - terdon♦
Jika Anda bersikeras. Bukan masalah saya. - muru


Anda dapat melakukan sesuatu seperti ini:

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

Atau:

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

Metode pertama mengasumsikan awalan tetap, menghapusnya dan memeriksa nilainya.

Metode kedua mengasumsikan sufiks panjang tetap (dan awalan tetap yang sama) dan bergantung pada fakta itu; dan itu, sementara 201 datang sebelum 31 secara leksikografis, tidak seperti itu sebelumnya 031.

Uji ini dengan echo perintah, dan setelah Anda yakin itu daftar file yang benar, gunakan rm sebagai gantinya.


3
2017-09-27 14:33



tidak satupun dari mereka berfungsi: / - Tak
@ user1460166 ah, itu mungkin karena pencocokan regex. Saya akan memperbaruinya. - muru
masih tidak bekerja. btw, filenya adalah .png :) - Tak
@ user1460166 dapatkah Anda mengatakan bagaimana cara kerjanya? - muru
Saya membuka terminal, cd ke folder kemudian salin baris Anda dan tempelkan, tetapi file tidak dihapus - Tak


Solusi shell POSIX

solusi pertama terdon  bergantung pada ekspansi brace, yang merupakan milik bash dan kshNamun tidak dapat digunakan dalam standar /bin/sh shell, yang pada Ubuntu adalah symlinked ke /bin/dash.

Dalam kasus di mana Anda harus bergantung /bin/sh untuk portabilitas skrip Anda, biasanya ada dua cara untuk mendekati ini. Satu akan melalui globbing. Hanya cd folderA dan dari sana lari rm a_*. Cara lain, akan menerapkan C-gaya untuk menggunakan alternatif loop while <CONDITION>;do ...done dalam bahasa shell dan memformat angka dengan printf:

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

Perhatikan bahwa di sini saya gunakan echo. Menggantikan echo "$filename" dengan rm ./"$filename" atau rm -- "$filename" ketika Anda siap untuk menghapus file. Juga perhatikan, bahwa ini harus dilakukan ketika Anda sudah melakukannya cded ke direktori yang diinginkan.

(ab) menggunakan awk

Awk menjadi bahasa mirip C yang bagus dapat membantu kita dalam dua cara: (1) kita dapat menghasilkan nama file dengan for-loop dan memformatnya melalui sprintf berfungsi, dan (2) menghapus file tersebut via system() perintah, yang akan meneruskan nama file kami dan rm perintah untuk /bin/sh :

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

Perl

Melanjutkan ide pendekatan portabel di mana kita "menghasilkan" nama file, kita bisa melakukan hal yang sama di Perl:

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

0
2017-11-18 18:17