Mengapa 'find -delete' menghapus semua file dalam direktori secara rekursif

15

Jadi perilaku unix berikut ini hanya merugikan saya:

> touch foo
> touch bar
> ls  
bar  foo
> find . -name '*oo' -delete
> ls
bar
> touch baz
> ls
bar  baz
> find . -delete -name '*ar'
> ls
> #WHAAAT?

Bagaimana ini masuk akal?

mszep
sumber
2
Pertanyaan ini terkait, mungkin menarik bagi pembaca di masa depan. unix.stackexchange.com/questions/101282/...
Bernhard

Jawaban:

14

Baris perintah find dibuat dari berbagai jenis opsi, yang digabungkan untuk membentuk ekspresi.

The findpilihan -deleteadalah tindakan.
Itu berarti dijalankan untuk setiap file yang cocok sejauh ini.
Sebagai opsi pertama setelah jalur, semua file dicocokkan ... oops!

Ini berbahaya - tetapi halaman manual setidaknya memiliki peringatan besar :

Dari man find:

ACTIONS
    -delete
           Delete  files; true if removal succeeded.  If the removal failed, an
           error message is issued.  If -delete fails, find's exit status  will
           be nonzero (when it eventually exits).  Use of -delete automatically
           turns on the -depth option.

           Warnings: Don't forget that the find command line is evaluated as an
           expression,  so  putting  -delete first will make find try to delete
           everything below the starting points you specified.  When testing  a
           find  command  line  that  you later intend to use with -delete, you
           should explicitly specify -depth in order to avoid later  surprises.
           Because  -delete  implies -depth, you cannot usefully use -prune and
           -delete together.


Dari lebih lanjut di man find:

EXPRESSIONS
    The expression is made up of options (which affect overall operation rather
    than  the  processing  of  a  specific file, and always return true), tests
    (which return a true or false value), and actions (which have side  effects
    and  return  a  true  or false value), all separated by operators.  -and is
    assumed where the operator is omitted.

    If the expression contains no actions other than  -prune,  -print  is  per‐
    formed on all files for which the expression is true.


Saat mencoba apa yang findakan dilakukan perintah:

Untuk melihat seperti apa perintahnya

find . -name '*ar' -delete

akan menghapus, pertama-tama Anda dapat mengganti tindakan -deletedengan tindakan yang lebih tidak berbahaya - seperti -flsatau -print:

find . -name '*ar' -print

Ini akan mencetak file mana yang dipengaruhi oleh tindakan.
Dalam contoh ini, -cetak dapat ditinggalkan. Dalam hal ini, tidak ada tindakan sama sekali, jadi yang paling jelas ditambahkan secara implisit: -print. (Lihat paragraf kedua bagian "EKSPRESI" yang dikutip di atas)

Volker Siegel
sumber
Saya kira saya hanya idiot karena tidak membaca manual pertama .. Tapi itu tampak begitu mudah untuk hanya menambahkan -deletebendera :-) Tapi apakah ada alasan orang akan pernah lakukan find . -deletebukan rm -rf .? Atau apakah itu hanya terjadi dengan cara findmem-parsing dan memproses argumennya?
mszep
1
Oh, saya sepenuhnya setuju bahwa sintaks sangat berbahaya - tetapi itu sulit untuk dihindari, karena itu hanya kasus khusus dari sintaks ekspresi baris comman dari find, yang sangat kuat. Kuat seperti dalam " Gergaji mesin yang kuat ".
Volker Siegel
bukankah halaman manual yang dikutip mengatakan warning: use -depth when testing stuff you later want to -deleteyang tidak Anda lakukan sebagai contoh praktis?
pqnet
Oh, benar - masalahnya adalah tajuknya - saya bermaksud mengilustrasikan penggunaan cetak di tempat -hapus seperti -nopsi; Perintah pertama seharusnya tidak memiliki penggunaan praktis sama sekali, tentu saja; Saya akan mengubahnya.
Volker Siegel
9

Dalam findurutan argumen penting, banyak.

Argumen dapat berupa opsi, tes, dan tindakan. Anda biasanya harus menggunakan opsi terlebih dahulu, lalu menguji, lalu bertindak.

Kadang find- kadang bahkan memperingatkan Anda tentang kemungkinan pemesanan yang buruk (misalnya ketika Anda menggunakan -maxdepthsetelah argumen lain), tetapi yang lain tampaknya tidak.

Apa yang find . -delete -name '*ar'dilakukan adalah:

  1. Menemukan file dan direktori pada direktori saat ini.
  2. Hapus SEMUA karena mereka ditemukan!
  3. Kemudian lihat apakah mereka dinamai seperti '* ar' (bagian ini tidak memiliki efek sekarang).

Apa yang mungkin ingin Anda lakukan adalah:

find -name '*ar' -delete

Ini akan, untuk setiap file, melihat apakah itu cocok '*ar', dan hanya jika memenuhi syarat itu akan menghapus file.

Maaf jika Anda tahu terlambat.

LatinSuD
sumber