find: -exec için argüman eksik


206

Bugün bir komutla bana yardım edildi, ama işe yaramıyor gibi görünüyor. Bu komut:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 && rm {}\;

Kabuk geri döner

find: missing argument to `-exec'

Ne temelde yapmaya çalışıyorum (diğer dizinleri varsa) özyinelemeli bir dizin üzerinden gitmek ve .rmdosya türlerinde ffmpeg komutunu çalıştırmak ve dosya türlerine dönüştürmek olduğunu .mp3. Bu yapıldıktan sonra .rm, yeni dönüştürülen dosyayı kaldırın .

Bu konuda herhangi bir yardım için teşekkür ederim.

Yanıtlar:


340

Bir -execkomut a ile sonlandırılmalıdır ;(bu nedenle genellikle yazmanız \;veya ';'kabuk tarafından yorumlanmasından kaçınmanız gerekir ) veya a +. Fark şudur ki ;, komut dosya başına bir kez +çağrılır, mümkün olduğunca az kez çağrılır (genellikle bir kez, ancak bir komut satırı için maksimum uzunluk vardır, bu yüzden bölünebilir) tüm dosya adlarıyla . Bu örneğe bakın:

$ cat /tmp/echoargs
#!/bin/sh
echo $1 - $2 - $3
$ find /tmp/foo -exec /tmp/echoargs {} \;
/tmp/foo - -
/tmp/foo/one - -
/tmp/foo/two - -
$ find /tmp/foo -exec /tmp/echoargs {} +
/tmp/foo - /tmp/foo/one - /tmp/foo/two

Komutunuzun iki hatası var:

İlk olarak, kullanın {};, ancak ;kendi başına bir parametre olmalıdır.

İkincisi, komut &&. “Run find komutunu belirttiniz ve bu başarılı olduysa {};.” Adlı dosyayı kaldırın . Komutta kabuk şeylerini kullanmak istiyorsanız -exec, bunu açıkça bir kabukta çalıştırmanız gerekir.-exec sh -c 'ffmpeg ... && rm' .

Ancak {} 'i bash komutunun içine eklememelisiniz, özel karakterler olduğunda sorunlara neden olur. Bunun yerine, sonradan kabuğa ek parametreler iletebilirsiniz -c command_string(bkz. man sh):

$ ls
$(echo damn.)
$ find * -exec sh -c 'echo "{}"' \;
damn.
$ find * -exec sh -c 'echo "$1"' - {} \;
$(echo damn.)

Gördüğünüz gibi $ilk örnekte bu şey kabuk tarafından değerlendirilir. $(rm -rf /):-) adlı bir dosya olduğunu düşünün

(Yan not: Bu -gerekli değildir, ancak komuttan sonraki ilk değişken $0, normalde çalıştırılan programın adını içeren ve bunu bir parametreye ayarlamak özel bir değişken olan değişkene atanır , ancak kazanılmış olsa da muhtemelen burada herhangi bir zarara yol açmaz, bu yüzden bunu sadece -başlatacağız ve başlayacağız $1.)

Yani emriniz şöyle bir şey olabilir

find -exec bash -c 'ffmpeg -i "$1" -sameq "$1".mp3 && rm "$1".mp3' - {} \;

Ama daha iyi bir yol var. destekleri bulmak andve orböylece gibi şeyler yapabilirsiniz find -name foo -or -name bar. Ancak bu -exec, komut başarılı bir şekilde çıkarsa true değerini ve değilse false değerini değerlendirir. Bu örneğe bakın:

$ ls
false  true
$ find * -exec {} \; -and -print
true

Yalnızca komut başarıyla gerçekleştirildiyse yazdırır, trueancak bunu gerçekleştirir, ancak yapmaz false.

Böylece, bir ile zincirlenmiş iki exec deyimini kullanabilirsiniz -andve ikincisi sadece birincisi başarılı bir şekilde çalıştırıldıysa çalıştırılır.


3
Anahtar, Marian'ın "the; kendi başına bir argüman" çizgisi gibi görünüyor, bunu benim için, ampul bilge ve kod örneğim için yaptı. Teşekkürler.
Mart'ta pjammer

3
-Exec'de okuduğum en iyi açıklama hakkında. Son derece güçlü ama bunun için doğru sözdizimini elde etmek her zaman zor. Bu birkaç şeyi daha açık hale getirdi. Özellikle komutu ayrı kabuğa sarma. Güzel. Teşekkürler.
Eurospoofer

3
Unutmayın -andve -ortaşınabilir değildir. POSIX belirtir -ave-o aslında -aher zaman varsayılır (dolayısıyla gerekli değildir).
gniourf_gniourf

Ayrıca sonlandırıcıdan önce bir boşluk olmalıdır. Ör "\;"işe vermez " \;"does
frmdstryr

56

Şimdi anladım. Bir komutta exec'de iki komut çalıştırmanız gerektiğinde, aslında iki ayrı exec'ye sahip olmanız gerekir. Bu sonunda benim için çalıştı.

find . -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 \; -exec rm {} \;

Silinecek dosya değişkenini alıp almayacağından emin değil misiniz? Durumun bu olup olmadığını bilen var mı?
Abs

7
Bu tür şeyleri test etmek echoiçin komutlardan önce bir tane ekleyin ve ne işe yaradığını görün.
Marian

2
@Marian, echooldukça güvenilmez - echo "one argument"ve arasındaki farkı söyleyemezsiniz echo one argument(ikincisinin çıktısı yanlıştır, çünkü aslında echoiki tamamen bağımsız argüman geçirir). -exec bash -c 'printf "%q " "$@"' _ ffmpeg -i {} -sameq {}.mp3 \; -printf '\n'DOS satırlarını ve diğer tuhaflıkları algılayabilmeniz için çıktıyı yazdırılamaz karakterleri görünür hale getirecek şekilde yazdıracak gibi bir şey yapmak çok daha iyidir .
Charles Duffy

52

Her birinin önüne bir boşluk koymayı deneyin \;

İşler:

find . -name "*.log" -exec echo {} \;

Çalışmıyor:

find . -name "*.log" -exec echo {}\;

1
Bu beni sık sık etkiliyor. Bu günlerden birinde, varsayılan olarak bir boşluk ekleyeceğim.
harperville

Benim için Windows 7 altında Cygwin'de tam tersi çalışıyor: önce boşluk yok \; boşluk ile çalışır - yapmaz. Ama eğer \, önce boşluk ile kaldırırsanız; çalışır ve daha önce boşluk bırakmaz; sadece burada anlatıldığı gibi değil.
WebComer

7

Sadece bilginiz için:
Sadece bir Cygwin sisteminde "find -exec" komutunu kullanmayı denedim (Windows'ta öykünülen UNIX) ve orada noktalı virgülden önce ters eğik çizginin kaldırılması gerekiyor gibi görünüyor:
find ./ -name "blabla" -exec wc -l {} ;


Gerçekten kafam karıştı. find /etc/nginx -name '*.conf' -exec echo {} ;ve find /etc/nginx -name '*.conf' -exec echo {}\;aynı sonucu verdi. :(
Kirby

Windows için Git ile birlikte gelen Bash kabuğunu çalıştırıyorum ve Dustin Cowles'ın cevabı benim için çalışıyor. Başka bir deyişle: tırnak işareti yok, noktalı virgülle kaçan ters eğik çizgi, boşluk {}.
mamacdon

Anlamda bir fark yoktur, ancak bazı durumlarda ters eğik çizgi koymanız gerekir, bazı durumlarda koyamazsınız ve yine diğer durumlarda seçebilirsiniz.
Dominique

2

Herkes Amazon Opsworks Chef bash komut dosyalarında benzer bir "eksik -exec argümanlar" görürse, ben \ kaçmak için başka bir ters eğik çizgi eklemek gerekiyordu;

bash 'remove_wars' do
  user 'ubuntu'
  cwd '/'
  code <<-EOH
    find /home/ubuntu/wars -type f -name "*.war" -exec rm {} \\;
  EOH
  ignore_failure true
end

2

Ayrıca, başka biri "-exec için" find: eksik argüman "a sahipse, bu yardımcı olabilir:

Bazı kabuklarda kaçmayı yapmanız gerekmez, yani “;” nin önünde “\” gerekmez.

find <file path> -name "myFile.*" -exec rm - f {} ;

2
;Alıntılanan ya da burada kaçan o okuduğu, kabuk tarafından değil tüketilebilir demektir olmamak find. Ayrıca, -fve - fiki farklı şeylerdir.
Charles Duffy

1

Bence biraz kaçman gerekiyor.

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i {} \-sameq {}.mp3 \&\& rm {}\;

0

Hem {} hem de &&, komut satırı tarafından genişletilmesi nedeniyle sorunlara neden olur. Denemenizi öneririm:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i \{} -sameq \{}.mp3 \; -exec rm \{} \;

Exec'deki ilk komut başarılı olursa ve exec'deki ikinci komut yürütülürse, {}doğru dosyayı silmek için değişkene yine de erişimi olur mu?
Abs

Neye {}genişlediğini düşünüyorsun? Olduğu gibi kalacak iki nokta veya virgül içermediği sürece.
Marian

0

{}Ve arasına boşluk bırakmalısınız\;

Yani komut şöyle olacak:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 && rm {} \;

-4

Hâlâ "find: eksik argümanı -exec'e" alıyorsanız, yürütme bağımsız değişkenini tırnak içine almayı deneyin.

find <file path> -type f -exec "chmod 664 {} \;"
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.