`Bul` -exec seçeneğini anlama


53

Kendimi sürekli sözdizimini ararken buluyorum

find . -name "FILENAME"  -exec rm {} \;

temel olarak -execparçanın tam olarak nasıl çalıştığını görmüyorum çünkü . Parantezlerin, ters eğik çizginin ve noktalı virgülün anlamı nedir? Bu sözdizimi için başka kullanım örnekleri var mı?


11
@Philippos: Amacınızı anlıyorum. Lütfen, man sayfalarının bir referans olduğunu, yani sözdizimini aramak için konuyu anlayanlar için yararlı olduğunu unutmayın. Konuya yeni giren biri için, genellikle yararlı olmak için şifreli ve resmidirler. Kabul edilen cevabın, man sayfasının girişi ile yaklaşık 10 katı olduğunu göreceksiniz ve bunun bir nedeni var.
Zsolt Szilagy

6
Eski POSIX mansayfası bile okuyor Bir yardımcı program_adı veya yalnızca "{}" iki karakterini içeren argüman, bana yetecek gibi görünen geçerli yol adıyla değiştirilecek. Ek olarak -exec rm {} \;, aynen sorunuzda olduğu gibi bir örnek var . manGünlerimde , "büyük gri duvar" dan başka hiçbir kaynak yoktu, basılı sayfaların kitapları (kağıt depodan daha neşeliydi). Bu yüzden konuya yeni giren biri için bunun yeterli olduğunu biliyorum. Son sorunuz burada sormak için adil. Maalesef @Kusalananda da kendimde buna bir cevap yok.
Philippos

1
Comeon @ Philippos. Gerçekten de Kusalananda'ya manpage üzerinde düzelmediğini mi söylüyorsun? :-)
Zsolt Szilagy

1
@allo xargsBazen kullanışlı olsa da, findonsuz komut vermek için birden çok yol argümanını iletebilir. -exec command... {} +( +yerine \;) command...uygun olandan sonra birçok yolu geçer (her işletim sisteminin bir komut satırının ne kadar olabileceği konusunda kendi sınırı vardır). Ve benzeri xargs, +bir nihayetti formu find'ın -execeylem da çalışacak command...sınırı içinde sığmayacak kadar birçok yol vardır nadir durumlarda birden çok kez.
Eliah Kagan

2
@ ZsoltSzilagy Ne demedim, ne de demek istedim. Seni çok iyi besledi, kendin yiyecek yaşta olduğunu düşünüyorum. (-;
Philippos

Yanıtlar:


90

Bu cevap aşağıdaki bölümlerde gelir:

  • Temel kullanımı -exec
  • -execİle birlikte kullanmaksh -c
  • kullanma -exec ... {} +
  • kullanma -execdir

Temel kullanımı -exec

-execSeçenek, bağımsız değişken olarak isteğe bağlı argümanlar bir dış yardımcı alır ve çalıştırır.

Dize {}verilen komutun herhangi bir yerinde mevcutsa, onun her bir örneği o anda işlenmekte olan yol adıyla değiştirilecektir (örn. ./some/path/FILENAME). Çoğu kabukta, iki karakterin {}alıntılanması gerekmez.

Komutun nerede bittiğini bilmek ;için bir for ile sonlandırılması findgerekir (daha sonra başka seçenekler de olabilir). Kabuktan korunmak için ;, \;veya olarak belirtilmesi gerekir ';', aksi takdirde kabuk findkomutun sonu olarak görür .

Örnek ( \ilk iki satırın sonunda sadece satır devam ediyor):

find . -type f -name '*.txt'      \
   -exec grep -q 'hello' {} ';'   \
   -exec cat {} ';'

Bu -type f, isimleri *.txtgeçerli dizindeki veya altındaki desene uyan tüm normal dosyaları ( ) bulacaktır . Daha sonra dizenin hellokullanarak bulunan herhangi bir dosyada ortaya çıkıp çıkmadığını test eder grep -q(herhangi bir çıktı üretmez, sadece bir çıkış durumu). Dizeyi içeren dosyalar catiçin dosyanın içeriğini terminale vermek için çalıştırılır.

Her biri , tıpkı olduğu gibi ve yaptığı -execyollarda bir "test" gibi davranır . Komut sıfır bir çıkış durumu verirse ("başarı" anlamına gelir), komutun bir sonraki kısmı dikkate alınır, aksi halde komut bir sonraki yol adı ile devam eder. Bu, yukarıdaki örnekte, dizeyi içeren dosyaları bulmak , ancak diğer tüm dosyaları yoksaymak için kullanılır.find-type-namefindfindhello

Yukarıdaki örnekte, en yaygın kullanılan iki kullanım örneği gösterilmektedir -exec:

  1. Aramayı daha da kısıtlamak için bir test olarak.
  2. Bulunan yol adı üzerinde bir tür eylem gerçekleştirmek için (genellikle, ancak findkomutun sonunda gerekli değildir ).

-execİle birlikte kullanmaksh -c

Yürütülebilir komut -execisteğe bağlı değişkenlerle birlikte harici bir yardımcı programla sınırlıdır. Kabuk yapılarını, fonksiyonlarını, koşullarını, boru hatlarını, yönlendirmeleri vb. -execKullanarak bir sh -cçocuk kabuğu gibi bir şey içine sarılmadıkça doğrudan kullanmak mümkün değildir .

Eğer bashözellikler gerekliyse, bash -cyerine kullanın sh -c.

sh -c/bin/shkomut satırında verilen bir komut dosyasıyla çalışır , ardından bu komut dosyasına isteğe bağlı komut satırı argümanları uygulanır.

Kullanmadan sh -ckendi başına kullanmanın basit bir örneği find:

sh -c 'echo  "You gave me $1, thanks!"' sh "apples"

Bu, alt kabuk betiğine iki argüman iletir:

  1. Dize sh. Bu $0, betiğin içinde olduğu gibi mevcut olacak ve eğer iç kabuk bir hata mesajı veriyorsa, onu bu dizeyle ön ekleyecektir.

  2. Argüman senaryodaki applesgibi mevcuttur $1ve daha fazla argüman olsaydı, o zaman bunlar şu gibi mevcut olurdu $2, $3vs. Listede de mevcut olurdu "$@"( $0bunun bir parçası olmayacak olanlar hariç "$@").

Bu, birlikte -execbulunan yamalar üzerinde etkili olan rasgele karmaşık komut dosyaları oluşturmamıza izin verdiği için birlikte kullanışlıdır find.

Örnek: Belirli bir dosya adı sonekine sahip tüm normal dosyaları bulun ve dosya adı sonekini, soneklerin değişkenlerde tutulduğu başka bir sonekle değiştirin:

from=text  #  Find files that have names like something.text
to=txt     #  Change the .text suffix to .txt

find . -type f -name "*.$from" -exec sh -c 'mv "$3" "${3%.$1}.$2"' sh "$from" "$to" {} ';'

İçteki betiğin içinde $1dize text, $2dize olacak txtve bizim için $3her ne findbulduysa olacaktır. Parametre genişlemesi ${3%.$1}yol adını alır ve sonekini .textondan kaldırır .

Veya, dirname/ kullanarak basename:

find . -type f -name "*.$from" -exec sh -c '
    mv "$3" "$(dirname "$3")/$(basename "$3" ".$1").$2"' sh "$from" "$to" {} ';'

veya, dahili komut dosyasına eklenen değişkenlerle:

find . -type f -name "*.$from" -exec sh -c '
    from=$1; to=$2; pathname=$3
    mv "$pathname" "$(dirname "$pathname")/$(basename "$pathname" ".$from").$to"' sh "$from" "$to" {} ';'

Bu son varyasyonda, değişkenlerin fromve toalt kabuktaki değişkenlerin harici komut dosyasında aynı ada sahip değişkenlerden farklı olduğunu unutmayın.

Yukarıdaki isteğe bağlı bir karmaşık komut çağrı doğru yolu -execile find. findGibi bir döngüde kullanma

for pathname in $( find ... ); do

hata eğilimli ve inelegant (kişisel görüş). Dosya adlarını boşluklarda bölüyor, dosya ismini globbing'i çağırıyor ve ayrıca kabuğun findilk tekrarını çalıştırmadan önce tüm sonucunu genişletmeye zorluyor .

Ayrıca bakınız:


kullanma -exec ... {} +

;Sonunda ile ikame edilebilir +. Bu find, verilen komutu her bulunan yol adı için bir defadan çok mümkün olduğu kadar çok argümanla (bulunan yol adlarıyla) çalıştırmaya neden olur . Dize {} bunun +çalışması için hemen önce gerçekleşmesi gerekir .

find . -type f -name '*.txt' \
   -exec grep -q 'hello' {} ';' \
   -exec cat {} +

Burada, findortaya çıkan yol adlarını toplayacak ve bir catkerede mümkün olduğunca çoğunu çalıştıracaksınız .

find . -type f -name "*.txt" \
   -exec grep -q "hello" {} ';' \
   -exec mv -t /tmp/files_with_hello/ {} +

Aynı şekilde, burada mvmümkün olduğunca az sayıda idam olacak. Bu son örnek mvcoreutil'den GNU gerektiriyor (bu -tseçeneği destekliyor ).

Kullanarak -exec sh -c ... {} +aynı zamanda karmaşık olan rasgele bir komut ile yol adlarının kümesi üzerinde döngü için etkili bir yoldur.

Temel bilgiler kullanımdakiyle aynıdır -exec sh -c ... {} ';', ancak komut dosyası artık daha uzun bir argüman listesi alıyor. Bunlar "$@"betiğin içinde ilmek alınarak ilmeklenebilir .

Dosya adı soneklerini değiştiren son bölümden örnek:

from=text  #  Find files that have names like something.text
to=txt     #  Change the .text suffix to .txt

find . -type f -name "*.$from" -exec sh -c '
    from=$1; to=$2
    shift 2  # remove the first two arguments from the list
             # because in this case these are *not* pathnames
             # given to us by find
    for pathname do  # or:  for pathname in "$@"; do
        mv "$pathname" "${pathname%.$from}.$to"
    done' sh "$from" "$to" {} +

kullanma -execdir

Ayrıca -execdir(çoğu finddeğişken tarafından uygulanır , ancak standart bir seçenek değildir).

Bu -exec, verilen kabuk komutunun, mevcut çalışma dizini olarak bulunan yol adının dizini ile yürütüldüğü ve bulunan yol adının bulunduğu yol adının bulunduğu yol işaretiyle çalıştırılan farkla aynı şekilde çalışır {}(ancak GNU find, taban adının yanında ./, BSD ile findbunu yapmayacağım).

Örnek:

find . -type f -name '*.txt' \
    -execdir mv {} done-texts/{}.done \;

Bu, her bulunan *.txt-file dosyasını, dosyanın bulunduğu dizindeki önceden var olan bir done-textsalt dizine taşır . Dosya ayrıca ona sonek eklenerek yeniden adlandırılır ..done

Bu, -execdosyanın {}yeni adını oluşturmak için bulunan dosyanın adının adını almak zorunda kalacağımız için biraz daha zor olacaktır . Dizini düzgün bir şekilde {}bulmak için done-textsdizin ismine de ihtiyacımız var .

Bununla birlikte -execdir, bazı şeyler daha kolay hale gelir.

Bunun -execyerine kullanarak ilgili işlem -execdirbir alt kabuk kullanmak zorunda kalacak:

find . -type f -name '*.txt' -exec sh -c '
    for name do
        mv "$name" "$( dirname "$name" )/done-texts/$( basename "$name" ).done"
    done' sh {} +

veya,

find . -type f -name '*.txt' -exec sh -c '
    for name do
        mv "$name" "${name%/*}/done-texts/${name##*/}.done"
    done' sh {} +

7
-execbir program ve argümanlar alır ve çalıştırır; bazı kabuk komutları yalnızca bir programdan ve argümanlardan oluşur, ancak bir çoğu değildir. Bir kabuk komutu yönlendirme ve borulama içerebilir; -execYapamazsınız (bütün findyönlendirilebilir rağmen ). Bir kabuk komutu ; && ifetc kullanabilir ; -execyapamam, ancak -a -obazılarını yapabilir. Bir kabuk komutu bir takma ad veya kabuk işlevi veya yerleşik olabilir; -execyapamam. Bir kabuk komutu vars'ı genişletebilir; -execYapamam (kutuyu çalıştıran dış kabuğa rağmen find). Bir kabuk komutu $(command)her seferinde farklı şekilde kullanılabilir; -execyapamam. ...
dave_thompson_085

... Bir kabuk komutu glob olabilir, -execolamaz - finddosyalar üzerinde çoğu globun yaptığı gibi yineleyebilse de, nadiren aranıyor.
dave_thompson_085

@ dave_thompson_085 Elbette, kabuk komutunun shkendisi de olabilir , ki tüm bunları
yapabilme kabiliyetine sahip

2
Burada bir kabuk komutunun yanlış olduğunu söylemek, find -exec cmd arg \;bir kabuk komut satırını yorumlamak için bir kabuk çağırmaz, execlp("cmd", "arg")doğrudan çalışır , execlp("sh", "-c", "cmd arg")(bunun için kabuğun yerleşik execlp("cmd", "arg")değilse eşdeğerini yapması gerekir cmd).
Stéphane Chazelas

2
Tüm findargümanların ardı ardına -execgelip gelmediğini ;veya +argümanlarla birlikte yürütmek için komutun yapıldığını, argümanın her bir örneğinin {}geçerli dosyayla (with ;) ve {}daha önce +bir dosya listesi ile değiştirilmeden önceki argüman olarak yapıldığını netleştirebilirsiniz. ayrı argümanlar olarak ( {} +durumda). IOW -exec, a veya ile sonlandırılan birkaç argüman alır . ;{} +
Stéphane Chazelas 26:17
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.