-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.