Bagaimana cara menghapus semua file dalam direktori kecuali beberapa?

123

Saya perlu menghapus semua file dalam direktori, tetapi mengecualikan beberapa dari mereka. Misalnya, dalam direktori berisi file a b c ... z, saya harus menghapus semua kecuali untuk udan p. Apakah ada cara mudah untuk melakukan ini?

Ashot
sumber
Jawaban di bawah ini jauh lebih baik, tetapi Anda bisa membuat file untuk menyimpan read-only, delete all, dan kemudian mengubahnya kembali ke izin aslinya (selama Anda tidak menggunakan rm -f). Anda harus tahu izin apa yang harus dipulihkan dan Anda harus tahu bahwa tidak perlu menulis akses kepada mereka selama proses. Inilah sebabnya mengapa jawaban lain lebih baik.
Joe
1
Jika Anda juga ingin menghapus file tersembunyi jalankan shopt -s dotglobsebelum menjalankan rm (...).

Jawaban:

108

Apa yang saya lakukan dalam kasus itu adalah mengetik

rm *

Lalu saya tekan Ctrl+ X, *untuk membuka * ke semua nama file yang terlihat.

Kemudian saya bisa menghapus dua file yang ingin saya simpan dari daftar dan akhirnya mengeksekusi baris perintah.

Der Hochstapler
sumber
25
Saya kira ini hanya berfungsi selama daftar file yang *mengembang juga tidak terlalu lama. : -}
Frerich Raabe
9
Esc diikuti oleh * juga akan memperluas "*".
slowpoison
2
@SantoshKumar: Itu tidak masuk akal bagi saya. Ekspansi akan selalu berfungsi, tidak tergantung pada perintah apa yang ingin Anda gunakan sesudahnya.
Der Hochstapler
2
@ OliverSalzburg Maaf, kombinasinya sedikit membingungkan. Saya pikir Anda harus menulis seperti Ctrl+ Shift+ x+*
Santosh Kumar
2
@SantoshKumar: Tapi itu bukan kombinasi.
Der Hochstapler
143

Untuk rmsemua kecuali u,pdalam bash ketik saja:

rm !(u|p)

Ini membutuhkan opsi berikut untuk ditetapkan:

shopt -s extglob

Lihat lebih lanjut: glob - Greg's Wiki

sparkie
sumber
1
Anda harus mengaktifkan ekstglobbing: shopt -s extglob
sparkie
18
Anda perlu shopt -s extglob, @Ashot. Juga, ini hanya file, bukan direktori, itulah sebabnya saya menghapus -rfopsi dalam perintah Anda.
slhck
4
Jika Anda perlu mengecualikan satu file dari pilihan file, coba ini: rm !(index).html. Ini akan menghapus semua file yang diakhiri dengan ".html" dengan pengecualian "index.html".
mzuther
71

Anda dapat gunakan find

find . ! -name u ! -name p -maxdepth 1 -type f -delete
  • ! Meniadakan ekspresi berikutnya
  • -name menentukan nama file
  • -maxdepth 1akan membuat proses pencarian direktori yang ditentukan saja ( findsecara default melintasi direktori)
  • -type f hanya akan memproses file (dan bukan untuk direktori misalnya)
  • -delete akan menghapus file

Anda kemudian dapat menyesuaikan kondisi dengan melihat halaman manual find

Memperbarui

  • Ingatlah bahwa urutan elemen ekspresi signifikan (lihat dokumentasi)
  • Uji perintah Anda terlebih dahulu dengan menggunakan -printalih-alih-delete

    find . ! -name u ! -name p -maxdepth 1 -type f -print
Matteo
sumber
5
urutan predikat sangat penting di sini. Jika satu dimasukkan -deletesetelah .itu akan menjadi bencana (akan menghapus semua file dalam CWD)
Michał Šrajer
Ini bisa ditulis lebih ringkas sebagaifind . -maxdepth 1 -type f -name '[^up]' -delete
kojiro
4
@ Kojiro ya tapi hanya untuk file yang hanya satu huruf. Dengan nama yang lebih kompleks, regex bisa berantakan.
Matteo
2
findadalah sahabat saya, terutama ketika ada terlalu banyak file untuk glob
Terence Johnson
43

Sederhana:

mvfile yang Anda inginkan di direktori atas, rmdirektori dan kemudian mvkembali.

pengguna176581
sumber
13
Offcourse, mv mereka ke direktori yang lebih tinggi. Cobalah untuk tidak memindahkan mereka ke subdirektori yang Anda hapus ...
Konerak
@Konerak: rmtanpa -rtidak akan menghapus subdirektori.
reinierpost
11
Ini akan menimpa file dengan nama yang sama di direktori tujuan
Matteo
7
Saya downvoting ini karena sementara itu bisa berguna, itu juga non-atom dan secara efektif menghapus semua file dari direktori selama periode waktu yang singkat; ini tidak dapat diterima jika, misalnya, file-file tersebut dibagikan di jaringan.
sam hocevar
15

Agak mirip dengan jawaban ini tetapi tidak ada opsi khusus yang diperlukan, sejauh yang saya tahu berikut ini adalah fungsionalitas "kuno" yang didukung oleh shell (menyerupai) / bin / sh yang menyerupai (misalnya bash, zsh, ksh, dll)

rm [^up]
hlovdal
sumber
2
Ini berfungsi untuk nama file 1-char. Untuk nama yang lebih panjang, jawaban sparkie lebih baik.
glenn jackman
3
Apa yang salah dengan itu rm [^up]*? Saya sering melakukan hal serupa.
CVn
3
@ MichaelKjörling - ini akan menghapus semua file yang dimulai dengan u atau p, bukan hanya file dengan nama u dan p. Saya pikir OP (@Ashot) berarti az dan u, p, dll. secara simbolis dan tidak secara harfiah.
Sudipta Chatterjee
4
@ HobbesofCalvin Itu akan menghapus semua file yang tidak dimulai dengan u atau p, bukan yang dimulai dengan mereka.
rjmunro
@rjmunro - terima kasih, ketinggalan yang itu! :)
Sudipta Chatterjee
11

Melakukannya tanpa menemukan:

ls | grep -v '(u|p)' | xargs rm

(Sunting: "u" dan "v", seperti di tempat lain di sini, digunakan sebagai versi umum seluruh regex. Jelas Anda ingin berhati-hati untuk melabuhkan regex Anda untuk menghindari pencocokan terlalu banyak hal.)

Anda pasti akan menginginkan skrip jika Anda akan melakukan banyak hal, seperti yang disarankan orang lain.

tquid
sumber
grep tidak akan menangani regexpt yang diperluas secara default: baik menggunakan -Eatauegrep
Matteo
2
ini akan mengecualikan file apa pun yang mengandung a uatau ap
Matteo
@ Matteo Tidak itu tidak akan. Grep tidak mengambil file, tetapi mengambil output dari perintah ls. Anda sedang memikirkan sesuatu seperti di grep -L (u|p)' * | xargs rmmana -Lberarti daftar nama file yang tidak mengandung kecocokan.
rjmunro
4
Oh, maksud Anda file apa pun yang namanya mengandung uatau p, bukan file apa pun yang mengandung a uatau a p. Itu betul. Anda dapat memperbaikinya dengan menggunakanegrep -v '^(u|p)$'
rjmunro
1
Berikut ini hapus semuanya kecuali kecocokan ini! ls | grep -v 'vuze\|progs' | xargs rm -rf
Nick
6

Dalam zsh:

setopt extended_glob  # probably in your .zshrc

kemudian

rm ^(u|p)

atau

rm *~(u|p)

Yang kedua akan bekerja bahkan jika Anda memiliki ^di $histcharsuntuk substitusi sejarah, dan tentu saja Anda dapat menempatkan segumpal sewenang-wenang sebelum ~.

Poolie
sumber
5

GLOBIGNORE mengambil daftar yang dipisahkan oleh titik dua

GLOBIGNORE=u:p
rm *
W_Whalley
sumber
12
Ini tidak berfungsi pada shell saya (GNU bash 4.1.5 (1)). Pastikan untuk mengujinya terlebih dahulu dengan sesuatu yang sedikit kurang berbahaya daripadarm atau di direktori pengujian!
CVn
3

Kembali di era floppy saya memiliki file executable bernama "Kecuali" yang akan memindahkan hal-hal dari direktori saat ini sementara dan menjalankan perintah, sehingga Anda bisa mengatakan:

kecuali * .txt del *. *

untuk menghapus semuanya kecuali file teks Anda.

Ini akan menjadi hal yang cukup sepele untuk diterapkan sebagai skrip shell dan jika ini adalah jenis hal yang Anda kemungkinan akan lakukan lebih dari dua kali sepertinya itu akan menjadi ide yang baik.

Bill K
sumber
2
Itu mengingatkan saya pada hal yang sama. Tetapi untuk sementara pindah dari folder mungkin bukan ide yang baik di era multitasking :)
Sedat Kapanoglu
3
 find . -maxdepth 1 ! -name "u" ! -name "p" -type f -exec rm -rf {} \;

Ini akan menghapus semua file kecuali u dan p di unix

pengguna1803687
sumber
2

Bagi mereka yang lebih memilih untuk menentukan pola mengecualikan kompleks sewenang-wenang (mencakup semua nama file yang terkena dampak) dalam emacs regexp penuh sesak, gaya posix-awk atau posix-extended (lihat menemukan halaman manual) Saya akan merekomendasikan yang ini. Tidak termasuk udan pdalam direktori saat ini dalam contoh ini. Ini mungkin berguna untuk skrip.

find -regextype posix-awk ! -regex './(u|p)' -print0 | xargs -0 rm -rf
sparkie
sumber
Anda perlu menentukan direktori sebelum ekspresi (`find. -Regextype ...).
Matteo
-regextypehanya akan bekerja pada versi GNU
Matteo
tidak - versi temukan saya (debian squeeze) secara definitif tidak memerlukan direktori eksplisit sebelum ekspresi jika direktori saat ini harus digunakan
sparkie
@sparke: ini hanya berfungsi pada implementasi GNU
Matteo
@ sparkie: tidak mendefinisikan direktori (parameter pertama) findadalah perpanjangan findperintah GNU . Hal yang sama berlaku untuk -regextypeopsi. Selain itu, perintah Anda akan menghapus file dalam subdirektori juga, sedangkan pertanyaan awal dengan jelas bertanya tentang file dalam direktori.
Mikko Rantalainen
1

Saya selalu menggunakan:

rm [a-o,q-t,v-z]*

Ini akan memungkinkan Anda untuk menentukan seberapa rinci Anda ingin membuatnya. Jadi jika Anda ingin menghapus file o dan Z Anda dapat menggunakan:

rm [a-o,z]*
J Baron
sumber
1

Versi lain menggunakan xargs:

ls -1 | grep -v do_not_delete | xargs -I files rm "files"

Catatan yang xargs -Idiperlukan untuk menangani nama file termasuk spasi dengan benar.

sebhofer
sumber
1

Lagi:

for FILE in ./*; do if [[ $FILE != ./u* ]] || [[ $FILE != ./p* ]];then rm $FILE; fi; done;

Agak panjang dan saya tidak tahu apakah Anda dapat dengan mudah membuatnya menjadi fungsi yang dapat dengan mudah mengakomodasi dan sejumlah argumen, tetapi berfungsi dengan baik.

Dan itu murni kebaikan pesta.

dylnmc
sumber
1

Berikut varian lainnya. Anda dapat mengetik:

rm -i *

atau:

rm --interactive *

Jadi rmakan meminta Anda untuk mengonfirmasi penghapusan setiap file.

idzikovsky
sumber
1

Menggunakan:

find . -type f ! -name 'u' ! -name 'p' ! -name '*.ext' -delete
find . -type d ! -name 'u' ! -name 'p' ! -name '*.ext' -delete

untuk menghapus semua file termasuk direktori, kecuali file u, p dan .ext.

Renzo Fabián
sumber
0

Cara sederhana yang sulit dikacaukan: misalkan Anda ingin menghapus semuanya kecuali * .pdf:

mkdir tmp
mv *.pdf tmp
rm *
mv tmp/* .
rm -r tmp
talloaktrees
sumber