-Exec başarısız olursa nasıl başarısız bulurum?


26

Bu komutu kabukta çalıştırdığımda (boş olmayan bir dizinde):

find . -exec invalid_command_here {} \;

Bunu anladım:

find: invalid_command_here: No such file or directory
find: invalid_command_here: No such file or directory
find: invalid_command_here: No such file or directory

(ve her dosya için vb.)

findİlk hatadan sonra başarısız olmam gerekiyor . Bu işe almak için herhangi bir yolu var mı? xargsYolumda boşluklar olduğu için kullanamıyorum , ancak hata kodu döndürmek için bunu çağıran komut dosyasına ihtiyacım var.

Yanıtlar:


30

Bu bir sınırlamadır find. POSIX standardı dönüş durumu belirtir findbir hata dizinleri sonrasında ise olması koşuluyla, 0; Yürütülen komutların dönüş durumu buna girmez.

Komutların durumlarını bir dosyaya veya bir tanımlayıcıya yazmasını sağlayabilirsiniz:

find_status_file=$(mktemp findstatus)
: >"$find_status_file"
find  -exec sh -c 'trap "echo \$?" EXIT; invalid_command "$0"' {} \;
if [ -s "$find_status_file" ]; then
  echo 1>&2 "An error occurred"
fi
rm -f "$find_status_file"

Keşfettiğiniz gibi başka bir yöntem, xargs kullanmaktır. xargsKomutlar her zaman tüm dosyaları işler ancak komutların herhangi bir sıfırdan farklı statü dönerse durumunu 1 döndürür.

find  -print0 | xargs -0 -n1 invalid_command

Diğer bir yöntem ise findkabukta özyinelemeli kürecikten kaçınmak ve kullanmaktır: **/herhangi bir alt derinliğin derinliği anlamına gelir. Bu sürüm 4 veya bash üstü gerektirir; macOS 3.x sürümünde takılı kaldığından port koleksiyonundan yüklemelisiniz. set -eSıfır olmayan bir durum döndüren ilk komuttaki komut dosyasını durdurmak için kullanın .

shopt -s globstar
set -e
for x in **/*.xml; do invalid_command "$x"; done

Bash 4.0 - 4.2 arasında, bunun işe yaradığını ama genellikle arzu edilmeyen dizinlere sembolik bağlar koyduğunu unutmayın.

Eğer bash yerine zsh kullanırsanız özyinelemeli globbing, kutudan çıkarmadan çabuk çalışır. Zsh, OSX / macOS'ta varsayılan olarak bulunur. Zsh ile yazabilirsiniz

set -e
for x in **/*.xml; do invalid_command "$x"; done

xargsYaklaşım genel olarak çalışır ama bir türlü üzerinde kırar bash -ckomutları. Örneğin: find . -name '*.xml' -print0 | xargs -0 -n 1 -I '{}' bash -c "foo {}". Bu, birkaç kez find . -name '2*.xml' -print0 | xargs -0 -n 1 -I '{}' foo {}yürütülürken, bir kez yürütülür ve başarısız olur. Neden bir fikrin var mı?
DKroot

@DKroot Asla {}içini kullanmayın bash -c. Bu dosya adını alır ve doğrudan shell komutunun içine ekler. Dosya adı, kabukta boşluklar gibi özel bir anlamı olan karakterler içeriyorsa, kabuk bu özel karakterleri bu şekilde yorumlar. Bir kabuğa ihtiyacınız varsa {}, örneğin ayrı bir argüman olarak iletin bash -c 'foo "$0"' {}( örneğin $0, etrafındaki çift tırnak işaretine de dikkat edin ).
Gilles

Tamam, soruları bir kenara bırakmak, neden ilk hatada durmuyor? find . -name '*' -print0 | xargs -0 -n 1 -I '{}' bash -c 'foo "$0"' {}
DKroot

@DKroot Neden bir hatayla durdu? xargs her zaman tüm öğelerde komutu çalıştırır.
Gilles

Bu cevabı kullanmaya çalışıyorum: xargs ( find . -print0 | xargs -0 -n1 invalid_command) yaklaşımı. Bu doğru ilk hatada durur: find . -name '*' -print0 | xargs -0 -n 1 -I '{}' foo {}. Harika! Ancak aynı yaklaşım bash -c(yukarıda) ile çalışmaz . İkisi arasındaki tek fark bash -c.
DKroot

18

Bunun yerine bunu kullanabilirim:

find . -name *.xml -print0 | xargs -n 1 -0 invalid_command

3

xargstek bir seçenek. Bununla birlikte, bunu findkullanmak +yerine bununla birlikte yapmak gerçekten çok kolaydır \;:

-exec  utility_name  [argument ...]   {} +

Gönderen POSIX belgelerinde :

Birincil ifade bir artı işareti ile işaretlenirse, birincil her zaman doğru olarak değerlendirilir ve birincil değerlendirilen patnitler kümeler halinde toplanır. Yardımcı program_adı, her bir toplanmış yol adı için bir kez çağrılır. Her bir çağrı kümedeki son yol adı toplandıktan sonra başlamalı ve bulma aracı çıkmadan önce ve bir sonraki kümedeki ilk yol adı (varsa) bu birincil için toplanmadan önce tamamlanmalı, ancak aksi takdirde yapılan başvuruda belirtilmemişse belirtilmelidir. diğer primerlerin değerlendirilmesinden önce, sırasında veya sonrasında gerçekleşir. Herhangi bir başlatma çıkış durumu olarak sıfır olmayan bir değer döndürürse, bulma programı sıfır olmayan bir çıkış durumu döndürür.Yalnızca “{}” iki karakterini içeren bir argüman, toplanmış yol adları kümesiyle değiştirilir, her bir yol adı, çağrılan yardımcı programa, toplandığı sırayla ayrı bir argüman olarak iletilir. Herhangi bir iki veya daha fazla yol adının boyutu, yardımcı programın yürütülmesi sistemin {ARG_MAX} sınırının aşılmasına neden olmayacak şekilde sınırlandırılmalıdır. Yalnızca “{}” iki karakteri içeren birden fazla argüman varsa, davranış belirtilmez.

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.