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?

Riju Mahna
sumber
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
John1024
sumber
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
Jeff Schaller
sumber
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
Ishak
sumber
2

Jika Anda menggunakan zsh, maka Anda dapat:

setopt extended_glob # if you don't have it enabled

rm -rf myfolder/^test2
JoL
sumber
0

Diuji dengan perintah di bawah ini dan bekerja dengan baik

find  /home/myfolder -maxdepth 1 -type d ! -iname test2 -exec rm -rvf {} \;
Praveen Kumar BS
sumber
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