Memahami find (1) opsi -exec (kurung kurawal & tanda tambah)

17

Menggunakan perintah berikut, bisakah seseorang tolong jelaskan apa sebenarnya tujuan dari kurung kurawal ({}) dan tanda tambah (+)?

Dan bagaimana perintah beroperasi secara berbeda jika mereka dikeluarkan dari perintah?

find . -type d -exec chmod 775 {} +
Ryan Prentiss
sumber

Jawaban:

19

Kurung kurawal akan digantikan oleh hasil dari findperintah, dan chmodakan dijalankan pada masing-masing. The +merek findmencoba untuk menjalankan sebagai beberapa perintah mungkin (sehingga, chmod 775 file1 file2 file3sebagai lawan chmod 755 file1, chmod 755 file2, chmod 755 file3). Tanpa mereka perintah hanya memberikan kesalahan. Ini semua dijelaskan dalam man find:

-exec command ;

      Jalankan perintah ; true jika 0 status dikembalikan. Semua argumen berikut finddianggap sebagai argumen untuk perintah sampai argumen yang terdiri dari ' ;' ditemukan. String ' {}' diganti oleh nama file saat ini sedang diproses di mana-mana itu terjadi dalam argumen ke perintah, bukan hanya dalam argumen di mana itu sendirian, seperti dalam beberapa versi find. ...

-exec command {} +

      Varian -execaksi ini menjalankan perintah yang ditentukan pada file yang dipilih, tetapi baris perintah dibangun dengan menambahkan setiap nama file yang dipilih di akhir; jumlah total doa perintah akan jauh lebih sedikit daripada jumlah file yang cocok. ...

terdon
sumber
12

Selain jawaban terdon,

  • "Jelas" -exec …harus diakhiri dengan tanda titik koma ( ;) atau tanda tambah ( +). Titik koma adalah karakter khusus di shell (atau, setidaknya, setiap shell yang pernah digunakan), sehingga, jika akan digunakan sebagai bagian dari findperintah , itu harus melarikan diri atau dikutip ( \;, ";", atau ';').
  • Dengan -exec … ;, {}string dapat muncul beberapa kali dalam perintah, termasuk nol , atau dua atau lebih, di posisi apa pun.  Lihat ini untuk contoh mengapa Anda mungkin ingin melakukannya -exectanpa menggunakan {}.   Memiliki dua atau lebih penampilan berguna terutama karena, dalam (setidaknya) beberapa versi find, {}tidak perlu menjadi kata dengan sendirinya; dapat memiliki karakter lain di awal atau akhir; misalnya,

    find . -type f -exec mv {} {}.bak ";"
    

    Dengan -exec … +, {}string harus muncul sebagai argumen terakhir sebelum +. Perintah seperti

    find . -name "*.bak" -exec mv {} backup_folder +
    

    menghasilkan find: missing argument to ‘-exec’pesan kesalahan yang membingungkan .

    • Solusi untuk ini yang khusus untuk cpdan mvperintah adalah

      find . -name "*.bak" -exec mv -t backup_folder {} +
      

      atau

      find . -name "*.bak" -exec mv --target-directory=backup_folder {} +
      

    Itu {}harus kata dengan sendirinya; tidak dapat memiliki karakter lain di awal atau akhir. Dan, dalam (setidaknya) beberapa versi find, Anda mungkin tidak memiliki lebih dari satu {}.

  • Catatan kewarasan: Bisa dibilang

    Temukan . -nama "* .sh" -type f -executable -exec {} argumen opsional di sini ";"

    untuk menjalankan masing-masing skrip Anda. Tapi

    Temukan . -nama "* .sh" -type f -executable -exec {} +

    menjalankan salah satu skrip Anda, dengan nama semua yang lain sebagai parameter. Ini mirip dengan mengatakan

    ./*.sh
    

    sebagai perintah shell, kecuali findtidak menjamin bahwa ia mengurutkan hasilnya, jadi Anda tidak dijamin menjalankan aaa.sh ( *.shfile pertama menurut abjad Anda ) karena Anda akan menjalankannya ./*.sh.

  • Aspek findyang mungkin tidak begitu jelas bagi pemula adalah bahwa baris perintah, secara efektif, merupakan pernyataan yang dapat dieksekusi dalam bahasa misterius. Sebagai contoh,

    find . -name "*.sh" -type f -executable -print
    

    cara

    for each file
        if the file’s name matches `*.sh` (i.e., if it ends with `.sh`)
        then
            if it is a plain file (i.e., not a directory)
            then
                if it is executable (i.e., the appropriate `---x--x--x` bit is set)
                then
                    print the file’s name
                end if
            end if
        end if
    end loop
    

    atau, secara sederhana,

    for each file
        if the file’s name matches `*.sh`  AND  it is a plain file  AND  it is executable
        then
            print the file’s name
        end if
    end loop
    

    Beberapa -kata kunci adalah tindakan yang dapat dieksekusi dan tes. Secara khusus, ini berlaku untuk -exec … ;; sebagai contoh,

    find . -type f -exec grep -q cat {} ";" -print
    

    diterjemahkan menjadi

    untuk setiap file
        jika itu adalah file biasa (yaitu, bukan direktori)
        kemudian
            jalankan nama file grep -q cat
            jika proses berhasil (yaitu, keluar dengan status 0)
            kemudian
                cetak nama file
            berakhir jika
        berakhir jika
    akhir lingkaran

    yang akan mencetak nama semua file yang berisi string " cat". Dan, sementara ini adalah sesuatu yang grepdapat dilakukan sendiri (dengan opsi -l(huruf kecil L)), dapat berguna untuk menggunakannya dengan findmencari file yang berisi string tertentu DAN memiliki ukuran tertentu DAN dimiliki oleh pemilik tertentu DAN dimodifikasi dalam rentang waktu tertentu, ....

    Namun, ini tidak berhasil -exec … +. Karena -exec … +mengeksekusi satu perintah untuk banyak file, tidak masuk akal untuk menggunakannya sebagai kondisi logis di dalam satu for each file …loop.

  • Sisi lain dari di atas adalah bahwa findumumnya keluar dengan status keluar 0 kecuali Anda memberikan argumen yang tidak valid atau menemui direktori yang tidak dapat dibaca. Sekalipun program yang Anda jalankan gagal (keluar dengan status keluar bukan nol), findakan keluar dengan status keluar 0.  Kecuali  jika program yang Anda jalankan -exec … +gagal (keluar dengan status keluar bukan nol), findakan keluar dengan status keluar bukan nol.

Selain satu juta versi find(1) dan pengujian apa yang findsebenarnya dilakukan pada beberapa sistem, Spesifikasi Open Group Base Issue 7, 2013 Edition menyediakan beberapa informasi tentang apa yang findharus, boleh, dan tidak boleh dilakukan.

G-Man Mengatakan 'Reinstate Monica'
sumber
3
Berhati-hatilah karena contoh yang Anda gunakan ... -exec mv {} {}.bak ...tidak dijamin berfungsi seperti yang diharapkan dengan semua findimplementasi. Status standar POSIX {}harus muncul sendiri untuk selalu dikenali, jika tidak maka perilaku bebas untuk menjaga karakter tidak berubah atau untuk menggantinya dengan nama path. Dalam kasus sebelumnya, seluruh perintah Anda pada dasarnya akan menghapus semua file tetapi yang terakhir ditemukan ...
jlliagre