Ada 2 cara untuk membaca pertanyaan ini, dan jawaban yang ada mencakup kedua interpretasi: BAIK: (a) menyimpan file dengan nama yang ditentukan secara langsung terletak di direktori target dan - seperti yang rm -rtersirat - hapus semua yang lain, termasuk subdirektori - bahkan jika mengandung file dengan nama yang ditentukan; ATAU: (b) melintasi seluruh subtree dari direktori target dan, di setiap direktori, hapus semua file kecuali yang memiliki nama yang tercantum.
mklement0
Jawaban:
219
find [path]-type f -not -name 'textfile.txt'-not -name 'backup.tar.gz'-delete
Jika Anda tidak menentukan, -type ftemukan juga akan mendaftar direktori, yang mungkin tidak Anda inginkan.
Atau solusi yang lebih umum menggunakan kombinasi yang sangat berguna find | xargs:
Saya mendapatkan "kesalahan sintaksis dekat token yang tidak terduga` ('"ketika saya melakukannya shopt -s extglob; rm -rf !(README|LICENSE). Ada gagasan mengapa?
Dennis
@saya tidak ingat, maaf. Saya mungkin akhirnya menggunakan finddengan -deletepilihan.
Dennis
Ini adalah solusi terbaik untuk saya dan berfungsi secara default di Ubuntu 12.04.4 LTS saya tanpa perlu
shopt
3
@nic, @Dennis: Kesalahan sintaksis menunjukkan bahwa sesuatu yang LAIN daripada bashyang digunakan, misalnya dash, di mana extglobtidak didukung. Namun, dalam shell interaktifbash , perintah juga JUGA tidak akan berfungsi seperti yang dinyatakan, meskipun untuk alasan yang berbeda. Singkatnya: jalankan shopt -s extglobDENGAN SENDIRI; SEKALI SUKSES ENABLED (memverifikasi dengan shopt extglob), mengeksekusi rm -rf !(README|LICENSE). (Meskipun extglobbelum diaktifkan, !(...)dievaluasi oleh ekspansi sejarah SEBELUM perintah dieksekusi; karena ini kemungkinan gagal, perintah extglob
NEITHER
2
@nic, @Dennis, @ mklement0: Saya memiliki masalah yang sama dengan "kesalahan sintaksis dekat token tak terduga (" ketika menjalankan perintah dalam file .sh (#! / bin / bash) tetapi tidak ketika saya menjalankannya dalam perintah antarmuka baris. Ternyata selain shopt -s extglobmenjalankan dalam antarmuka baris perintah, saya harus menjalankannya kembali di dalam file skrip saya. Ini memecahkan masalah bagi saya.
Ini akan mencantumkan semua file di direktori saat ini, kemudian daftar semua yang tidak sesuai dengan kriteria Anda (waspadalah dengan nama direktori yang cocok) dan kemudian hapus.
Pembaruan : berdasarkan hasil edit Anda, jika Anda benar-benar ingin menghapus semuanya dari direktori saat ini kecuali file yang Anda daftarkan, ini dapat digunakan:
Ini akan membuat direktori cadangan /tmp_backup(Anda punya hak root, kan?), Pindahkan file yang Anda daftarkan ke direktori itu, hapus semua secara rekursif dalam direktori saat ini (Anda tahu bahwa Anda berada di direktori yang benar, bukan?), Pindah kembali ke direktori sekarang semuanya dari /tmp_backupdan akhirnya, hapus /tmp_backup.
Saya memilih direktori cadangan untuk di-root, karena jika Anda mencoba menghapus semuanya secara rekursif dari root, sistem Anda akan memiliki masalah besar.
Tentunya ada cara yang lebih elegan untuk melakukan ini, tetapi yang ini cukup mudah.
Bekerja dengan sangat baik dengan egrep, misalnya untuk membersihkan file lateks antara:find . | egrep -v "\.tex|\.bib" | xargs rm
mtsz
perintah luar biasa! untuk menghapus direktori, ubah saja ke rm -r
Aris
1
Jika Anda hanya ingin menghapus semua yang ada di direktori saat ini selain kriteria yang dikecualikan: find . -maxdepth 1 | grep -v "exclude these" | xargs rm -rbekerja lebih cepat karena tidak perlu menelusuri direktori yang tidak perlu.
billynoah
Re findpipeline: mengesampingkan masalah efisiensi (3 perintah digunakan untuk apa yang findbisa dilakukan sendiri), ini tidak akan berfungsi sebagaimana dimaksud dengan nama file dengan ruang yang disematkan dan berpotensi akan menghapus file yang salah.
mklement0
Perintah yang menyimpan file "yang akan disimpan" di lokasi lain ( /tmp_backup) tidak berakhir dengan baik jika terganggu — dari perspektif pengguna, semua file telah lenyap, kecuali mereka tahu ke mana harus mencari mereka untuk mendapatkannya kembali . Karena itu saya tidak mendukung strategi jenis ini.
Craig McQueen
20
Dengan asumsi bahwa file dengan nama-nama itu ada di banyak tempat di pohon direktori dan Anda ingin menyimpan semuanya:
find .-type f !-regex ".*/\(textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt\)"-delete
Pengaturan GLOBIGNORE seperti ini mengabaikan php dan sql dari wildcard yang digunakan seperti "ls *" atau "rm *". Jadi, menggunakan "rm *" setelah mengatur variabel hanya akan menghapus file txt dan tar.gz.
+1; Alternatif yang lebih sederhana untuk mengatur dan mengembalikan GLOBIGNOREvariabel adalah dengan menggunakan subkulit:(GLOBIGNORE='*.php:*.sql'; rm *)
mklement0
19
Saya lebih suka menggunakan daftar permintaan sub:
Ini lebih rumit karena Anda harus mengurus izin setelah Anda menyalinnya kembali.
Romulus
2
@RemusAvram Anda dapat menggunakan sakelar yang sesuai dengan cpatau rsyncuntuk mempertahankan izin. Bagaimanapun, ini hanyalah metode alternatif (diberikan sebagai saran) yang memiliki tempatnya di sini, sebagai jawaban untuk OP.
gniourf_gniourf
Ini mungkin tidak sesuai dalam banyak situasi di mana file yang disimpan secara aktif digunakan oleh proses lain. Itu juga rumit dari file yang akan dihapus hanya sebagian kecil dan sejumlah besar file yang terlibat.
codeforester
@ kodeforester: tentu. Tapi ada situasi di mana itu pantas, meskipun ... sebenarnya saya tidak benar-benar mengerti maksud dari komentar Anda :).
gniourf_gniourf
6
Anda dapat menulis untuk loop untuk ini ...%)
for x in*doif["$x"!="exclude_criteria"]then
rm -f $x;fidone;
Sedikit terlambat untuk OP, tapi semoga bermanfaat bagi siapa saja yang tiba di sini nanti oleh google ...
Saya menemukan jawabannya oleh @awi dan mengomentari -delete oleh @Jamie Bullock sangat berguna. Utilitas sederhana sehingga Anda dapat melakukan ini di direktori yang berbeda dengan mengabaikan nama / tipe file yang berbeda setiap kali dengan mengetik minimal:
rm_except (atau apa pun yang Anda ingin beri nama)
TIDAK berfungsi untuk file. rm !(myfile.txt)menghapus semua termasukmyfile.txt
khaverim
harus dieksekusi shopt -s extglobpertama seperti yang ditunjukkan oleh @ pl1nk
zhuguowei
Ya, sangat penting untuk mengaktifkan extended globbing ( extglob ) di bash, saya melakukan ini dalam rutinitas harian, lebih dari beberapa Mac di laboratorium: shopt -s extglobdan kemudian cd /Users/alumno/dan akhirnya rm -rf !(Applications|Virtualbox*VMs|Downloads|Documents|Desktop|Public|Library) Baca tentang globbing yang diperluas di sini
juanfal
4
Hanya:
rm $(ls -I "*.txt")#Deletes file type except *.txt
Setelah itu, loop semua file dalam direktori yang ingin Anda kecualikan, memeriksa apakah nama file dalam array yang tidak ingin Anda kecualikan; jika tidak maka hapus file tersebut.
for file in*;doif[[!" ${files[@]} "~="$file"]];then
rm "$file"fidone
Perbandingan regex tidak benar - ini akan mempertahankan file apa pun yang namanya adalah substring dari salah satu file yang dilindungi (meskipun ruang di sekitarnya agak mengurangi itu; tetapi nama file dapat berisi spasi). Anda harus mengumpulkan array dari semua file, lalu kurangi file yang ingin Anda kecualikan dari array itu, lalu hapus file yang tersisa.
tripleee
-1
Karena belum ada yang menyebutkan ini, dalam satu kasus tertentu:
OLD_FILES=`echo *`... create new files ...
rm -r $OLD_FILES
(atau adil rm $OLD_FILES)
atau
OLD_FILES=`ls *`... create new files ...
rm -r $OLD_FILES
Anda mungkin perlu menggunakan shopt -s nullglobjika beberapa file ada di sana atau tidak di sana:
Jawaban yang ada oleh Leonardo Hermoso melakukan ini dengan bug yang lebih sedikit. Ini akan gagal untuk nama file dengan spasi; menggunakan array secara elegan memecahkan masalah tertentu (dan juga yang kurang penting menghindari penggunaan huruf besar untuk variabel pribadinya, yang umumnya harus dihindari).
tripleee
-3
Daripada menggunakan perintah langsung, silakan pindahkan file yang diperlukan ke temp dir di luar dir saat ini. Kemudian hapus semua file menggunakan rm *atau rm -r *.
Kemudian pindahkan file yang diperlukan ke direktori saat ini.
Ini mungkin tidak sesuai dalam banyak situasi di mana file yang disimpan secara aktif digunakan oleh proses lain. Itu juga rumit dari file yang akan dihapus hanya sebagian kecil dan sejumlah besar file yang terlibat.
codeforester
-3
Hapus semuanya kecuali file.name:
ls -d /path/to/your/files/*|grep -v file.name|xargs rm -rf
Ini akan gagal total dan dapat menyebabkan kehilangan data jika direktori / file Anda memiliki spasi atau karakter yang tidak biasa. Anda seharusnya tidak menguraikan ls. mywiki.wooledge.org/ParsingLs
rm -r
tersirat - hapus semua yang lain, termasuk subdirektori - bahkan jika mengandung file dengan nama yang ditentukan; ATAU: (b) melintasi seluruh subtree dari direktori target dan, di setiap direktori, hapus semua file kecuali yang memiliki nama yang tercantum.Jawaban:
Jika Anda tidak menentukan,
-type f
temukan juga akan mendaftar direktori, yang mungkin tidak Anda inginkan.Atau solusi yang lebih umum menggunakan kombinasi yang sangat berguna
find | xargs
:misalnya, hapus semua file non txt di direktori saat ini:
The
print0
dan-0
kombinasi diperlukan jika ada ruang di salah satu nama file yang harus dihapus.sumber
find . -type f -not -name '*ignore1' -not -name '*ignore2' | xargs rm
-print0 | xargs -0 rm --
Anda hanya bisa-delete
Extglob (Pencocokan Pola yang Diperluas) harus diaktifkan dalam BASH (jika tidak diaktifkan):
sumber
shopt -s extglob; rm -rf !(README|LICENSE)
. Ada gagasan mengapa?find
dengan-delete
pilihan.bash
yang digunakan, misalnyadash
, di manaextglob
tidak didukung. Namun, dalam shell interaktifbash
, perintah juga JUGA tidak akan berfungsi seperti yang dinyatakan, meskipun untuk alasan yang berbeda. Singkatnya: jalankanshopt -s extglob
DENGAN SENDIRI; SEKALI SUKSES ENABLED (memverifikasi denganshopt extglob
), mengeksekusirm -rf !(README|LICENSE)
. (Meskipunextglob
belum diaktifkan,!(...)
dievaluasi oleh ekspansi sejarah SEBELUM perintah dieksekusi; karena ini kemungkinan gagal, perintahextglob
shopt -s extglob
menjalankan dalam antarmuka baris perintah, saya harus menjalankannya kembali di dalam file skrip saya. Ini memecahkan masalah bagi saya.find . | grep -v "excluded files criteria" | xargs rm
Ini akan mencantumkan semua file di direktori saat ini, kemudian daftar semua yang tidak sesuai dengan kriteria Anda (waspadalah dengan nama direktori yang cocok) dan kemudian hapus.
Pembaruan : berdasarkan hasil edit Anda, jika Anda benar-benar ingin menghapus semuanya dari direktori saat ini kecuali file yang Anda daftarkan, ini dapat digunakan:
Ini akan membuat direktori cadangan
/tmp_backup
(Anda punya hak root, kan?), Pindahkan file yang Anda daftarkan ke direktori itu, hapus semua secara rekursif dalam direktori saat ini (Anda tahu bahwa Anda berada di direktori yang benar, bukan?), Pindah kembali ke direktori sekarang semuanya dari/tmp_backup
dan akhirnya, hapus/tmp_backup
.Saya memilih direktori cadangan untuk di-root, karena jika Anda mencoba menghapus semuanya secara rekursif dari root, sistem Anda akan memiliki masalah besar.
Tentunya ada cara yang lebih elegan untuk melakukan ini, tetapi yang ini cukup mudah.
sumber
find . | egrep -v "\.tex|\.bib" | xargs rm
find . -maxdepth 1 | grep -v "exclude these" | xargs rm -r
bekerja lebih cepat karena tidak perlu menelusuri direktori yang tidak perlu.find
pipeline: mengesampingkan masalah efisiensi (3 perintah digunakan untuk apa yangfind
bisa dilakukan sendiri), ini tidak akan berfungsi sebagaimana dimaksud dengan nama file dengan ruang yang disematkan dan berpotensi akan menghapus file yang salah./tmp_backup
) tidak berakhir dengan baik jika terganggu — dari perspektif pengguna, semua file telah lenyap, kecuali mereka tahu ke mana harus mencari mereka untuk mendapatkannya kembali . Karena itu saya tidak mendukung strategi jenis ini.Dengan asumsi bahwa file dengan nama-nama itu ada di banyak tempat di pohon direktori dan Anda ingin menyimpan semuanya:
sumber
Anda dapat menggunakan variabel lingkungan GLOBIGNORE di Bash.
Misalkan Anda ingin menghapus semua file kecuali php dan sql, maka Anda dapat melakukan hal berikut -
Pengaturan GLOBIGNORE seperti ini mengabaikan php dan sql dari wildcard yang digunakan seperti "ls *" atau "rm *". Jadi, menggunakan "rm *" setelah mengatur variabel hanya akan menghapus file txt dan tar.gz.
sumber
GLOBIGNORE
variabel adalah dengan menggunakan subkulit:(GLOBIGNORE='*.php:*.sql'; rm *)
Saya lebih suka menggunakan daftar permintaan sub:
sumber
Karena tidak ada yang menyebutkannya:
sumber
cp
ataursync
untuk mempertahankan izin. Bagaimanapun, ini hanyalah metode alternatif (diberikan sebagai saran) yang memiliki tempatnya di sini, sebagai jawaban untuk OP.:)
.Anda dapat menulis untuk loop untuk ini ...%)
sumber
Sedikit terlambat untuk OP, tapi semoga bermanfaat bagi siapa saja yang tiba di sini nanti oleh google ...
Saya menemukan jawabannya oleh @awi dan mengomentari -delete oleh @Jamie Bullock sangat berguna. Utilitas sederhana sehingga Anda dapat melakukan ini di direktori yang berbeda dengan mengabaikan nama / tipe file yang berbeda setiap kali dengan mengetik minimal:
rm_except (atau apa pun yang Anda ingin beri nama)
mis. untuk menghapus semuanya kecuali file teks dan foo.bar:
Mirip dengan @mishunika, tetapi tanpa klausa if.
sumber
Jika Anda menggunakan
zsh
yang sangat saya rekomendasikan.Dengan
extended_glob
sumber
Mencoba ini berhasil:
tetapi nama dengan spasi sulit (seperti biasa). Mencoba juga dengan
Virtualbox\ VMs
kutipan. Itu selalu menghapus direktori itu (Virtualbox VMs
).sumber
rm !(myfile.txt)
menghapus semua termasukmyfile.txt
shopt -s extglob
pertama seperti yang ditunjukkan oleh @ pl1nkshopt -s extglob
dan kemudiancd /Users/alumno/
dan akhirnyarm -rf !(Applications|Virtualbox*VMs|Downloads|Documents|Desktop|Public|Library)
Baca tentang globbing yang diperluas di siniHanya:
Atau:
sumber
ls
output bisa menjadi masalah. Lihat Di Sini untuk informasi terperinci.Buat file tidak berubah. Bahkan root tidak akan diizinkan untuk menghapusnya.
Semua file lain telah dihapus.
Akhirnya, Anda dapat mengatur ulangnya agar dapat berubah.
sumber
Ini mirip dengan komentar dari @ siwei-shen tetapi Anda perlu
-o
bendera untuk melakukan beberapa pola. The-o
bendera singkatan dari 'atau'find . -type f -not -name '*ignore1' -o -not -name '*ignore2' | xargs rm
sumber
Anda dapat melakukan ini dengan dua urutan perintah. Pertama-tama tentukan array dengan nama file yang tidak ingin Anda kecualikan:
Setelah itu, loop semua file dalam direktori yang ingin Anda kecualikan, memeriksa apakah nama file dalam array yang tidak ingin Anda kecualikan; jika tidak maka hapus file tersebut.
sumber
Karena belum ada yang menyebutkan ini, dalam satu kasus tertentu:
(atau adil
rm $OLD_FILES
)atau
Anda mungkin perlu menggunakan
shopt -s nullglob
jika beberapa file ada di sana atau tidak di sana:tanpa nullglob,
echo *.sh *.bash
dapat memberi Anda "a.sh b.sh * .bash".(Setelah mengatakan semua itu, saya sendiri lebih suka jawaban ini , meskipun tidak bekerja di OSX)
sumber
Daripada menggunakan perintah langsung, silakan pindahkan file yang diperlukan ke temp dir di luar dir saat ini. Kemudian hapus semua file menggunakan
rm *
ataurm -r *
.Kemudian pindahkan file yang diperlukan ke direktori saat ini.
sumber
Hapus semuanya kecuali file.name:
sumber