Hapus semua file / direktori kecuali satu file

244

Saya memiliki direktori yang berisi banyak file. Saya ingin menghapus semua file kecuali file.txt. Bagaimana saya melakukan ini?

Ada terlalu banyak file untuk dihapus yang tidak diinginkan secara individual dan namanya terlalu beragam untuk digunakan * untuk menghapus semuanya kecuali file yang satu ini.

Seseorang menyarankan untuk menggunakan

rm !(file.txt)

Tapi itu tidak berhasil. Ia mengembalikan:

Badly placed ()'s 

OS saya adalah Scientific Linux 6.

Ada ide?

Kantura
sumber
13
pindahkan yang ingin kamu simpan, lalu rm yang lain?
Olivier Dulac
5
@OlivierDulac Apakah kita satu-satunya dua orang dalam pertanyaan ini yang tidak terlalu memikirkan pertanyaan?
Shadur
1
@shadur: baiklah, saya bisa mengaitkannya dengan mereka: oneliners itu menarik ... ^^
Olivier Dulac
1
Terima kasih, dan ya saya sedang mencari solusi satu baris. Ini terlalu memakan waktu untuk terus memindahkan file karena saya harus melakukan ini cukup sering.
Kantura

Jawaban:

288

POSIXly:

find . ! -name 'file.txt' -type f -exec rm -f {} +

akan menghapus semua file biasa (secara rekursif, termasuk yang tersembunyi) kecuali file.txt. Untuk menghapus direktori, ubah -type fke -type ddan tambahkan -ropsi ke rm.

Di bash, untuk menggunakan rm -- !(file.txt), Anda harus mengaktifkan extglob :

$ shopt -s extglob 
$ rm -- !(file.txt)

(atau menelepon bash -O extglob)

Perhatikan bahwa extglobhanya bekerja di bashdan keluarga shell Korn. Dan menggunakan rm -- !(file.txt)dapat menyebabkan Argument list too longkesalahan.

Di zsh, Anda dapat menggunakan ^untuk meniadakan pola dengan extendedglob diaktifkan:

$ setopt extendedglob
$ rm -- ^file.txt

atau menggunakan sintaksis yang sama dengan kshdan bashdengan opsi ksh_globdan no_bare_glob_qualdiaktifkan.

cuonglm
sumber
9
Menentukan direktori adalah praktik yang baik (jalur penuh dalam kasus ini? Atau mungkin menambahkan peringatan di sini bahwa perintah ini menghapus setiap file mulai dari direktori kerja saat ini ?). Saya juga biasanya menulis contoh dengan rmsebagai echo rmgantinya, dan meminta orang untuk hanya mengambil gema ketika mereka benar-benar yakin itu akan melakukan apa yang mereka inginkan. Selain itu, +1 untuk jawaban menyeluruh
Olivier Dulac
11
Saya sarankan -deletesebagai gantinya -exec, lebih pendek dan lebih mudah diingat
Izkata
6
@Izkata: -deletetidak didefinisikan oleh POSIX.
cuonglm
5
Bagaimana cara mengecualikan daftar file?
Meysam
5
@ Meysam - lihat jawaban saya untuk solusi yang akan menangani daftar file. Lain dengan findsolusi Gnouc yang dapat Anda lakukan ! \( -name one_file -o -name two_file \)dan seterusnya.
mikeserv
112

Lain mengambil arah yang berbeda (jika tidak ada spasi dalam nama file)

ls | grep -v file.txt | xargs rm

atau (berfungsi meskipun ada spasi dalam nama file)

ls | grep -v file.txt | parallel rm

dari man grep:

 -v, --invert-match
          Invert the sense of matching, to select non-matching lines.  (-v is specified by POSIX)
Sebastian
sumber
2
Ini tidak akan berfungsi jika nama file memiliki spasi ...
Matteo
1
Ciao @Matteo, ini berfungsi untuk file dengan spasi juga, tetapi Anda harus mengelilingi pola grep dengan tanda kutip, misalnya ls | grep -v "a file with spaces.bin" | xargs rm. Ini adalah grepsintaksis normal .
Sebastian
1
@ Sebastian Masalahnya bukan greptapi rm. rmakan mendapatkan daftar argumen yang dipisahkan oleh spasi. Coba touch 'a b'; touch 'c d'; ls | grep -v 'a b' | xargs rm: Anda akan mendapatkan rm: c: No such file or directorydanrm: d: No such file or directory
Matteo
1
Ya, ini adalah masalah umum. Lihat opsi -print0di finddan -0di xargs. Berikut ini solusinya, tetapi sedikit tidak nyaman. find . -maxdepth 1 -type f | grep -v 'a b' | tr '\n' '\0' | xargs -0 rm. Ngomong-ngomong, gnu parallelmenangani ini dengan baik (saya hampir selalu menggunakannya sebagai pengganti xargs:ls | grep -v 'a b' | parallel rm
Sebastian
1
Ini bukan hanya spasi, semuanya kosong dan baris baru, tetapi juga mengutip karakter (tunggal, tanda kutip ganda dan garis miring terbalik) dan nama file dimulai dengan -.
Stéphane Chazelas
32

Pertahankan salinan, hapus semuanya, pulihkan salinan:

{   rm -rf *
    tar -x
} <<TAR
$(tar -c $one_file)
TAR

Dalam satu baris:

{ rm -rf *; tar -x; } <<< $(tar -c $one_file)

Tapi itu membutuhkan shell yang mendukung string di sini.

mikeserv
sumber
10
Ini agak mengejutkan.
vschum
2
@Derek - silakan lihat hasil edit.
mikeserv
2
Tetapi jika ini terganggu setengah jalan, atau jika ada yang salah, file tersebut hilang.
kasperd
2
@kasperd - no. Hanya jika shell induk mati di antara waktu berjalan rmdan tar -x. rmdapat gagal sebanyak yang diinginkan.
mikeserv
2
Bukankah lebih efisien untuk memindahkannya ke direktori lain dan memindahkannya kembali? Kami tidak perlu berurusan dengan konten file, hanya dengan jalurnya.
leonbloy
23

Anda semua terlalu memikirkan ini.

cd ..
mv fulldir/file.txt /tmp/
rm -rf fulldir
mkdir fulldir
mv /tmp/file.txt fulldir/

Selesai.

EDIT Sebenarnya, lebih mudah:

cd ..
ln fulldir/file.txt ./
rm -rf fulldir
mkdir -p fulldir
mv file.txt fulldir/
Shadur
sumber
3
itu adalah hal yang sama dengan jawaban saya. exce [pt itu tidak kehilangan izin pada dir.
mikeserv
6
Jika itu adalah file besar di sistem file terpisah dari / tmp dan Anda mencoba untuk menghapus semuanya dari root filesystem ke bawah, maka memindahkannya ke tempat yang aman mungkin bukan pilihan.
Johnny
1
Ini jelas merupakan jawaban yang paling sederhana.
Ben Liyanage
17

Di OS Scientific Linux 6 saya ini berfungsi:

shopt -s extglob
rm !(file.txt)

Saya juga telah menginstal Debian 32bit pada Mesin Virtual. Di atas tidak berfungsi tetapi yang berikut ini tidak:

find . -type f ! -name 'file.txt' -delete
Kantura
sumber
1
Maksud Anda findsolusi yang saya berikan tidak berfungsi?
cuonglm
"tidak bekerja" atau "tidak bekerja". Ya, solusi menemukan Anda juga berfungsi. Terima kasih.
Kantura
1
Bisakah Anda membuatnya lebih detail? Bagaimana "tidak bekerja? Itu tidak menghapus file lain, atau dihapus file.txtatau apa pun?
cuonglm
Maksud saya bahwa pada OS Debian "$ rm! (File.txt)" mengembalikan "Badlyempatkan ()'s". Jadi saya mencoba "$ shopt -s extglob", tetapi ia kembali: "shopt: Command not found". Lalu saya mencoba solusi "menemukan". Itu berhasil.
Kantura
1
Oh, tentu saja itu tidak berhasil. shoptbukan tcshbuiltin.
cuonglm
10

Gunakan rm !("file.txt")sebagai gantirm !(file.txt)

www.wishinfo.net
sumber
4
Sama sekali tidak ada bedanya sama sekali. Masalahnya di sini adalah bahwa OP adalah 1) tidak menggunakan shell yang mendukung format ini dan 2) bahkan dalam bash, Anda harus mengaktifkannya dengan shopt -s extglob. Bagaimanapun, mengutip nama file sederhana seperti itu tidak akan membuat perbedaan.
terdon
1
Untuk menjaga hanya folder utils do - rm -rf! ("Utils")
James Jithin
7

Hanya untuk memberikan jawaban yang berbeda, Anda dapat menggunakan perilaku default rmyang tidak akan menghapus folder:

mkdir tmp && mv file.txt tmp  # create tmp dir and move files there
rm                            # delete all other files
mv tmp/* . && rm -rf tmp      # move all files back and delete tmp dir
Nithin
sumber
1

Saya menemukan bahwa pendekatan ini sangat sederhana, berfungsi, dan tidak memerlukan ekstensi khusus (yang saya tahu!)

ls --hide=file.txt | xargs rm
2-bit
sumber