wyrwać się z szukania, jeśli błąd -exec zawiedzie

14

Czy istnieje sposób na napisanie findtak, aby się zepsuł, jeśli jedna z -execoperacji zakończy się niepowodzeniem na pliku?

Np. ( javacJest dogodnie używany jako program, który może zwrócić kod wyjścia 1 dla niektórych plików i bez innego powodu):

$ echo "public classXX A{}" >> A.java
$ echo "public class B{}" >> B.java
$ find . -iname \*.java -exec javac {} \;
./A.java:1: error: class, interface, or enum expected
public classXX A{}
       ^
1 error

W powyższym przykładzie, mimo że execplik A.javanie powiódł się (i zwrócił kod wyjścia 1), findpolecenie kontynuowało i skompilowało plik B.java. Czy istnieje sposób na ucieczkę, findczy forzamiast tego powinienem użyć jakiejś formy ?

Moja wersja find:

$ find -version  | head -1
find (GNU findutils) 4.4.2
Marcus Junius Brutus
źródło

Odpowiedzi:

5

Myślę...

find ... -exec sh -c 'cmd "$0" || kill $PPID' \{\} \;

... powinien załatwić sprawę dla każdego find.

mikeserv
źródło
Dzięki @Gilles. Czego $0zrobić?
mikeserv
1
$0jest pierwszym argumentem do sh -c( $1jest drugi itd.) - konwencjonalnie nazwa wykonywanego programu, ale tutaj wykonujesz fragment kodu i przekazujesz przetwarzaną nazwę pliku, co $0ma sens (np. łatwo widzisz to w ps). Istnieje szkoła myślenia (do której oczywiście nie należę), która stwierdza, że $0zawsze powinna być wykonywalna, a ty powinieneś pisać sh -c 'cmd "$1" …' sh {}.
Gilles „SO- przestań być zły”
@Gilles - całkiem sprytny. Wielkie dzięki. Zorientowałem się w samochodzie w drodze do przedszkola, ale musiałem o tym myśleć przez kilka minut. To sprytne - wykorzystam to. To, co faktycznie kliknęło to dla mnie, to edycja, którą zapamiętałem, czytając Stephane'a na jednym z twoich własnych postów, w którym dodał on find-sh $0na końcu findwypowiedzi. Moim zdaniem wydaje się to bardziej przydatne, choć chyba najważniejsze jest to, czego szukasz na dłuższą metę.
mikeserv
Nie działa w powyższym przypadku. Po awarii find . -iname \*.java -exec sh -c 'javac "${0}" || kill '$$ {} \;pliku A.javai nadal kompiluje się plik B.java.
Marcus Junius Brutus
@MarcusJuniusBrutus - Naprawiłem to. Powinienem był zobaczyć twój komentarz wcześniej. Jeszcze raz przepraszam.
mikeserv
4

Przynajmniej z GNU findmożesz użyć:

find ... -exec ... -o -quit
Hauke ​​Laging
źródło
Wydaje mi się, że mam problem z wyjaśnieniem, gdzie exec się zatrzymuje, a zaczyna od -o. Oba find . -iname \*.java -exec javac {} -o -quit \;i find . -iname \*.java -exec javac {} \; -o -quit \;nie (na różne sposoby)
Marcus Junius Brutus
@MarcusJuniusBrutus \;jest potrzebny na końcu -exec(tzn. Wcześniej -o -quitw tym przypadku), ale może nie być nigdzie indziej.
Hauke ​​Laging
2
Korzystanie -exec ... -o -quitnie działa dla mnie. Nie przetwarza żadnych plików. Jednak działa ta linia: find . -iname \*.java -not -exec javac '{}' \; -quit: -quitnazywa jeśli -execjest fałszywe, tj. zwraca z niezerową.
savanto
find . -iname \*.java -exec javac {} \; -o -quitrównież nie przetwarza żadnych plików. O dziwo, find . -iname \* -exec echo 'foo' \; -o -quit robi „proces” pliki.
Marcus Junius Brutus
0

Zapoznaj się z findinstrukcją. Odpowiedź Hauke ​​zmotywowała mnie do spojrzenia, a wyszukiwanie QNX ma -abortopcję, która wydaje się podobna do -quitopcji GNU . Działa dla mnie, pod warunkiem że używam \(i \)grupuję wyrażenia:

find . -mtime -4 -name <pattern> \( -exec my_cmd {} \; -o  -abort \) 

Uwaga: bez parens przerywa pierwszy plik.

szałwia
źródło