Bagaimana saya bisa menghapus file bernomor dalam rentang yang diberikan?

16

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

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

Jawaban:

35

Dengan asumsi Anda tahu atau bisa menebak akhir kisaran, Anda bisa menggunakan ekspansi brace :

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, findcukup daftar semua file yang cocok a_*. Daftar ini diteruskan ke whileloop di mana setiap nama file dibaca ke dalam variabel $file. Kemudian, dengan menggunakan fitur manipulasi string bash , jika bagian numeriknya (cari mencetak file sebagai ./file, jadi ${file#./a_}cetak nomornya saja) 000750atau lebih besar, file tersebut dihapus. The -vhanya ada sehingga Anda dapat melihat file apa yang telah 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
terdon
sumber
Mengapa menghindari [[?
muru
1
@uru mengapa menggunakannya? [[misalnya tidak menyederhanakan hal-hal di sini [[ "${file#./a_}" > 000749 ]], bahkan tidak membuatnya lebih pendek. Saya tidak suka menggunakan sintaks yang tidak perlu dan ini bahkan akan bekerja di shell yang lebih sederhana dash.
Terdon
Karena [[menangani ruang dan keanehan lebih baik (saya tidak terlalu peduli untuk >keduanya).
muru
1
@uru ya, tapi [tidak masalah jika Anda mengutip variabel yang saya miliki, bekerja pada shell yang jauh lebih sederhana dan lebih sederhana.
terdon
Jika Anda bersikeras. Bukan masalah saya.
muru
3

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 dengan panjang tetap (dan awalan tetap umum) dan bergantung pada fakta itu; dan itu, sementara 201datang sebelum 31secara leksikografis, itu tidak terjadi sebelumnya 031.

Uji ini dengan echoperintah, dan setelah Anda yakin itu daftar file yang benar, gunakan rmsaja.

muru
sumber
tak satu pun dari mereka yang bekerja: /
Tak
@ user1460166 ah, itu mungkin karena pencocokan regex. Saya akan memperbaruinya.
muru
masih tidak bekerja. btw, file-file tersebut adalah .png :)
Tak
@ user1460166 dapatkah Anda mengatakan bagaimana ini tidak berfungsi?
muru
Saya membuka terminal, cd ke folder kemudian salin baris Anda dan rekatkan, tetapi file tidak dihapus
Tak
0

Solusi shell POSIX

Solusi pertama terdon bergantung pada ekspansi brace, yang merupakan properti dari , bashdan kshbagaimanapun itu tidak dapat digunakan dalam /bin/shshell standar , yang pada Ubuntu disinkronkan dengan /bin/dash.

Dalam kasus di mana Anda harus mengandalkan /bin/shportabilitas skrip Anda, umumnya ada dua cara untuk mendekati ini. Seseorang akan melalui globbing. Hanya cd folderAdan dari sana lari rm a_*. Cara lain, akan menerapkan C-style untuk alternatif loop menggunakan while <CONDITION>;do ...donedalam 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. Ganti echo "$filename"dengan rm ./"$filename"atau rm -- "$filename"ketika Anda siap untuk menghapus file. Perhatikan juga, bahwa ini harus dilakukan ketika Anda sudah cdmasuk 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 sprintffungsi, dan (2) menghapus file tersebut melalui system()perintah, yang akan melewati nama file dan rmperintah yang dihasilkan untuk /bin/sh:

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

Perl

Melanjutkan dengan gagasan pendekatan portabel di mana kita "menghasilkan" nama file, kita dapat melakukan hal yang sama di Perl:

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

Sesederhana

rm partialfilename* -f

Dalam contoh Anda itu

rm a_00075* -f
Vitaly Dubyna
sumber
1
Maaf untuk mengatakan, tapi itu bukan kisaran, itu semua file dimulai dengan a_00075...
Fabby
1
* adalah wildcard, OP sedang mencari jawaban tentang cara menghapus RANGE hal-hal ... misalnya jika Anda memiliki file 1 hingga 100, dan ingin menghapus # 41 hingga # 75
Joshua Besneatte