Bagaimana saya bisa menggunakan dua perintah bash di -exec dari perintah find?

32

Apakah mungkin untuk menggunakan 2 perintah di -execbagian findperintah?

Saya sudah mencoba sesuatu seperti:

find . -name "*" -exec  chgrp -v new_group {}  ; chmod -v 770 {}  \;

dan saya mendapatkan:

find: argumen yang hilang untuk -exec
chmod: tidak dapat mengakses {}: Tidak ada file atau direktori seperti itu
chmod: tidak dapat mengakses;: Tidak ada file atau direktori tersebut

Luc M
sumber

Jawaban:

44

Sedangkan untuk findperintah, Anda juga bisa menambahkan lebih banyak -execperintah dalam satu baris:

find . -name "*" -exec chgrp -v new_group '{}' \; -exec chmod -v 770 '{}' \;

Perhatikan bahwa perintah ini, dalam hasilnya, setara dengan menggunakan

chgrp -v new_group file && chmod -v 770 file

pada setiap file.

Semua find's parameter seperti -name, -exec, -sizedan sebagainya, sebenarnya tes : findakan terus berjalan satu per satu selama seluruh rantai sejauh ini dievaluasi untuk benar . Jadi setiap -execperintah berturut-turut dieksekusi hanya jika yang sebelumnya dikembalikan benar (yaitu 0status keluar dari perintah). Tetapi findjuga memahami operator logika seperti atau ( -o) dan tidak ( !). Oleh karena itu, untuk menggunakan rangkaian -exectes terlepas dari hasil sebelumnya, orang perlu menggunakan sesuatu seperti ini:

find . -name "*" \( -exec chgrp -v new_group {} \; -o -exec chmod -v 770 {} \; \)
rozcietrzewiacz
sumber
4
+1: Ya, itu cara paling elegan untuk melakukannya. Jika Anda dapat menjelaskan, mengapa Anda menggunakan '{}'(tanda kutip di sekitar kawat gigi), silakan kunjungi: unix.stackexchange.com/q/8647/4485
pengguna tidak diketahui
1
@user Sayangnya, saya tidak tahu apakah itu masih perlu. Saya melakukan beberapa tes sekarang dan belum menemukan situasi di mana itu akan mengubah apa pun. Saya kira itu hanya "latihan yang baik" yang akan mati.
rozcietrzewiacz
2
Kutipan penting untuk file dengan spasi di namanya.
naught101
17
find . -name "*" -exec sh -c 'chgrp -v new_group "$0" ; chmod -v 770 "$0"' {} \;
glenn jackman
sumber
@Gilles: Keajaiban -cpenanganan aneh $ 0 membuat saya berpikir ini salah setiap kali saya meliriknya, tapi itu pasti benar.
derobert
Saya suka shell eksplisit yang didefinisikan ...
Djangofan
Jawaban ini (dan jawaban Giles) sepertinya merupakan jawaban yang lebih baik untuk pertanyaan yang diberikan sh -c.
14

Perintah Anda pertama-tama diuraikan oleh shell menjadi dua perintah yang dipisahkan oleh a ;, yang setara dengan baris baru:

find . -name "*" -exec chgrp -v new_group {}
chmod -v 770 {} \;

Jika Anda ingin menjalankan perintah shell, aktifkan shell secara eksplisit dengan bash -c(atau sh -cjika Anda tidak peduli bahwa shell tersebut khusus bash):

find . -name "*" -exec sh -c 'chgrp -v new_group "$0"; chmod -v 770 "$0"' {} \;

Perhatikan penggunaan {}sebagai argumen ke shell; itu adalah argumen nol (yang biasanya merupakan nama shell atau skrip, tetapi ini tidak masalah di sini), karenanya dirujuk sebagai"$0" .

Anda dapat mengirimkan beberapa nama file ke shell sekaligus dan membuat shell mengulanginya, itu akan lebih cepat. Di sini saya lulus _sebagai nama skrip dan argumen berikut adalah nama file, yang for x(pintasan untuk for x in "$@") berulang.

find . -name "*" -exec sh -c 'for x; do chgrp -v new_group "$x"; chmod -v 770 "$x"; done' _ {} +

Perhatikan bahwa sejak bash 4, atau di zsh, Anda tidak perlu menemukan sama sekali di sini. Dalam bash, jalankan shopt -s globstar(taruh di Anda ~/.bashrc) untuk mengaktifkan **/berdiri untuk glob direktori rekursif. (Di zsh, ini aktif setiap saat.) Lalu

chgrp -v new_group -- **/*; chmod -v 770 -- **/*

atau jika Anda ingin agar file-file tersebut diulang secara berurutan

for x in **/*; do
  chgrp -v new_group -- "$x"
  chmod -v 770 -- "$x"
done

Satu perbedaan dengan findperintah adalah bahwa shell mengabaikan file dot (file yang namanya dimulai dengan a .). Untuk memasukkannya, dalam bash, set pertama GLOBIGNORE=.:..; di zsh, gunakan **/*(D)sebagai pola glob.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Jawaban ini (dan jawaban Glenn) sepertinya jawaban yang lebih baik untuk pertanyaan yang diberikan sh -c.