Hapus semua folder di dalam folder kecuali satu dengan nama tertentu


17

Saya perlu menghapus semua folder di dalam folder menggunakan skrip harian. Folder untuk hari itu perlu dibiarkan.

Folder 'myfolder' memiliki 3 sub folder: 'test1', 'test2' dan 'test3' Saya harus menghapus semua kecuali 'test2'.

Saya mencoba mencocokkan nama yang tepat di sini:

find /home/myfolder -type d ! -name 'test2' | xargs rm -rf

ATAU

find /home/myfolder -type d ! -name 'test2' -delete

Perintah ini selalu mencoba untuk menghapus folder utama 'myfolder' juga! Apakah ada cara untuk menghindari ini?


6
Di Unix dan Linux, kami menyebutnya "direktori", bukan "folder".
tchrist

1
Tergantung pada shell Anda, Anda mungkin perlu mengutip !operator itu: \!atau '!'.
Toby Speight

Jawaban:


32

Ini akan menghapus semua folder di dalamnya ./myfolderkecuali itu ./myfolder/test2dan semua kontennya akan dipertahankan:

find ./myfolder -mindepth 1 ! -regex '^./myfolder/test2\(/.*\)?' -delete

Bagaimana itu bekerja

  • find memulai perintah find.
  • ./myfoldermemberitahu find untuk memulai dengan direktori ./myfolderdan isinya.

  • -mindepth 1 tidak cocok dengan ./myfolderdirinya sendiri, hanya file dan direktori di bawahnya.

  • ! -regex '^./myfolder/test2\(/.*\)?' memberitahu find untuk mengecualikan ( !) file atau direktori yang cocok dengan ekspresi reguler ^./myfolder/test2\(/.*\)?. ^cocok dengan awal nama jalur. Ekspresi (/.*\)?cocok dengan (a) garis miring diikuti oleh apa pun atau (b) tidak ada sama sekali.

  • -delete memberitahu find untuk menghapus file yang cocok (yaitu, tidak dikecualikan).

Contoh

Pertimbangkan struktur direktori yang mirip;

$ find ./myfolder
./myfolder
./myfolder/test1
./myfolder/test1/dir1
./myfolder/test1/dir1/test2
./myfolder/test1/dir1/test2/file4
./myfolder/test1/file1
./myfolder/test3
./myfolder/test3/file3
./myfolder/test2
./myfolder/test2/file2
./myfolder/test2/dir2

Kita dapat menjalankan perintah find (tanpa -delete) untuk melihat apa yang cocok:

$ find ./myfolder -mindepth 1 ! -regex '^./myfolder/test2\(/.*\)?'
./myfolder/test1
./myfolder/test1/dir1
./myfolder/test1/dir1/test2
./myfolder/test1/dir1/test2/file4
./myfolder/test1/file1
./myfolder/test3
./myfolder/test3/file3

Kami dapat memverifikasi bahwa ini berfungsi dengan melihat file yang tersisa:

$ find ./myfolder
./myfolder
./myfolder/test2
./myfolder/test2/file2
./myfolder/test2/dir2

1
Alternatif untuk -prunemeninggalkan test2/*/subdirektori sendirian: kembali ke rm -rdan tambahkan -maxdepth 1.
Toby Speight

@ Isaac OK. Selesai (Juga, +1 untuk jawaban terbaik Anda.)
John1024

Kerja luar biasa !, tapi maaf: itu akan menghapus semua file di dalamnya ./myfolder. Anda memerlukan yang tidak ada (IMvhO) hanya-type d untuk direktori .
Isaac

Oke, ini seharusnya berfungsi seperti yang Anda inginkan:find ./myfolder -depth -mindepth 1 -maxdepth 1 -type d ! -regex '^./myfolder/test2\(/.*\)?'
Isaac

10

Menggunakan bash :

shopt -s extglob
rm -r myfolder/!(test2)/

Contoh:

$ tree myfolder/
myfolder/
├── test1
│   └── file1
├── test2
│   └── file2
└── test3
    └── file3

$ echo rm -r myfolder/!(test2)
rm -r myfolder/test1 myfolder/test3
$ rm -r myfolder/!(test2)
$ tree myfolder/
myfolder/
└── test2
    └── file2

1 directory, 1 file

5

tl; dr

find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 \
     -exec echo rm -rf '{}' \;

Hapus gema jika puas dengan daftar file.


Menggunakan -mindepth 1akan memastikan bahwa direktori teratas tidak dipilih.

$ find ./myfolder -mindepth 1 -type d
./myfolder/test2
./myfolder/test2/one
./myfolder/test2/two
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Tapi -not -name test2akan tidak menghindari subdirs dalam test2:

$ find ./myfolder -mindepth 1 -type d -not -name 'test2'
./myfolder/test2/one
./myfolder/test2/two
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Untuk melakukan itu, Anda perlu sesuatu seperti prune:

$ find ./myfolder -mindepth 1 -name test2 -prune -o -type d -print
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Tapi jangan gunakan delete, seperti yang tersirat depthdan itu akan mulai dihapus dari jalur terpanjang:

$ find ./myfolder -depth -mindepth 1 -name test2 -prune -o -type d -print
./myfolder/test/a1/a2/a3
./myfolder/test/a1/a2
./myfolder/test/a1
./myfolder/test

Gunakan salah satu rm -rf(hapus echojika Anda ingin benar-benar menghapus):

$ find ./myfolder -mindepth 1 -name test2 -prune -o -type d -exec echo rm -rf '{}' \;
rm -rf ./myfolder/test
rm -rf ./myfolder/test/a1
rm -rf ./myfolder/test/a1/a2
rm -rf ./myfolder/test/a1/a2/a3

Atau, gunakan jugamaxdepth jika yang Anda butuhkan adalah menghapus direktori (dan semua yang ada di dalamnya) (hapus echountuk benar-benar menghapus):

$ find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 -exec echo rm -rf '{}' \;
rm -rf ./myfolder/test

A -deletemasih akan gagal jika direktori tidak kosong:

$ find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 -delete
find: cannot delete ‘./myfolder/test’: Directory not empty

2

Jika Anda menggunakan zsh, maka Anda dapat:

setopt extended_glob # if you don't have it enabled

rm -rf myfolder/^test2

0

Diuji dengan perintah di bawah ini dan bekerja dengan baik

find  /home/myfolder -maxdepth 1 -type d ! -iname test2 -exec rm -rvf {} \;

Anda mengalami masalah yang sama dengan OP; listing / home / folder pada command-line (tanpa kritis -mindepth 1) membuat direktori teratas cocok dengan semua kriteria (itu adalah direktori dan itu tidak bernama "test2") sehingga dihapus.
Jeff Schaller
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.