-Exec find komutunda iki bash komutunu nasıl kullanabilirim?


32

Komut -execbölümünde 2 komut kullanmak mümkün müdür find?

Gibi bir şey denedim:

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

ve alıyorum:

find: eksik -exec
chmod argümanı : erişilemiyor {}: Böyle bir dosya veya dizin yok
chmod: erişemiyor;: Böyle bir dosya veya dizin yok

Yanıtlar:


44

findKomuta gelince , sadece -execarka arkaya daha fazla komut ekleyebilirsiniz :

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

Bu komutun sonuç olarak kullanmaya eşdeğer olduğunu unutmayın.

chgrp -v new_group dosyası && chmod -v 770 dosyası

her dosyada.

Tüm findgibi 'ın parametreleri -name, -exec, -sizeve bu yüzden, üzerinde aslında testleri : findBütün zincir şimdiye kadar hiç değerlendirmiştir sürece onları birer birer yayınlanmaya devam edecektir doğrudur . Böylece her ardışık -execkomut yalnızca önceki olanlar doğru döndüğünde (yani 0komutların çıkış durumları) yürütülür . Ama findaynı zamanda mantık operatörleri gibi anlar ya ( -o) ve değil ( !). Bu nedenle, önceki sonuçlardan bağımsız olarak bir -exectest zinciri kullanmak için , bunun gibi bir şey kullanmanız gerekir:

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

4
+1: Evet, bunu yapmanın en şık yolu. Neden kullandığınızı '{}'(diş tellerinin etrafındaki kesme işaretini) açıklayabilirseniz, lütfen şu adresi ziyaret edin: unix.stackexchange.com/q/8647/4485
— kullanıcı bilinmeyen

1
@ user Ne yazık ki, hala gerekli olup olmadığını bilmiyorum. Şimdi biraz test yaptım ve hiçbir şeyi değiştireceği bir durumla karşılaşmadım. Sanırım sadece "iyi uygulama" çıkacak.
— rozcietrzewiacz

2
Tırnaklar, adlarında boşluk olan dosyalar için önemlidir.
— naught101

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

@Gilles: -c0 doların tuhaf kullanım harikaları , ona her baktığımda bunun yanlış olduğunu düşünmeme neden oluyor, ama kesinlikle doğru.
— derobert

Tanımlanan açık kabuk gibi ...
— djangofan

Bu cevap (ve Giles'in cevabı) verilen soru için daha iyi cevap gibi görünüyor sh -c.

14

Komutunuz önce kabuk tarafından a ile ayrılan ve ;yeni bir satıra eşdeğer olan iki komuta ayrıştırılır :

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

Bir kabuk komutu çalıştırmak istiyorsanız, açıkça bir kabuğu çağırın bash -c(ya sh -cda kabuğun özel olarak bash olmasını umursamıyorsanız):

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

Kabuğa {}bir argüman olarak kullanımına dikkat edin; Bu, sıfırıncı argümandır (normalde kabuk veya komut dosyasının adıdır, ancak burada bunun önemi yoktur), bu nedenle referans olarak verilir "$0".

Bir seferde birden fazla dosya adını kabuğa iletebilir ve kabuğun içini yinelemesini sağlayabilirsiniz, daha hızlı olacaktır. Burada _komut dosyası adı olarak geçiyorum ve aşağıdaki argümanlar for x(kısayol için for x in "$@") yinelenen dosya adlarıdır .

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

Bash 4 veya zsh dilinde olduğundan, burada hiçbir şey bulmanıza gerek olmadığını unutmayın. Bash, özyinelemeli bir dizin glob için ayakta aktif hale shopt -s globstargetirmek için çalıştırın (içine koymak ~/.bashrc) **/. (Zsh'de, bu her zaman etkindir.) Sonra

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

veya dosyaların sırayla yinelenmesini istiyorsanız

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

Komuttaki bir fark find, kabuğun nokta dosyalarını (yani adı a ile başlayan dosyaları) görmezden gelmesidir .. Bunları dahil etmek için bash olarak ilk küme GLOBIGNORE=.:..; zsh içinde, **/*(D)glob kalıbı olarak kullanın .


Bu cevap (ve Glenn'in cevabı) verilen soru için daha iyi cevap gibi görünüyor sh -c.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.