Jak wykonać wiele poleceń podczas korzystania z funkcji Znajdź?

57

Próbuję uruchomić wiele poleceń na rzeczach, które znalazłem, jak mogę to osiągnąć?

find . -exec cmd1; cmd2

wydaje się nie działać; zamiast tego uruchamia cmd2 po wykonaniu cmd1 na każdym pliku.

Tamara Wijsman
źródło

Odpowiedzi:

40

W tej demonstracji użyję sh -c 'echo first; false'(lub true) po raz pierwszy -exec. To da jakieś wyjście, a także będzie miało wybrany efekt kodu wyjścia. Następnie echo secondzostanie wykorzystany do drugiego. Załóżmy, że w bieżącym katalogu jest jeden plik.

$ find . -type f -exec sh -c 'echo first; false' \; -exec echo second \;
first
$ find . -type f -exec sh -c 'echo first; true' \; -exec echo second \;
first
second
$ find . -type f \( -exec sh -c 'echo first; false' \; -false -o -exec echo second \; \)
first
second
$ find . -type f \( -exec sh -c 'echo first; false' \; -false -o -exec echo second \; \)
first
second

Prawdziwe polecenie tego typu wyglądałoby następująco:

find . -type f \( -exec command1 \; -false -o -exec command2 \; \)

W drugim zestawie nawiasach ucieczkowych grupuje dwie -execklauzule. -falseMiędzy nimi wymusza stan testu na „false” i -opowoduje, że następnego wyrazu (drugi -exec), aby być oceniane ze względu na -false.

Od man find:

wyrażenie1
wyrażenie2 Dwa wyrażenia z rzędu są łączone za pomocą domyślnych „i”; wyrażenie2 nie jest oceniane, jeśli wyrażenie1 jest fałszem.

wyrażenie1 -a wyrażenie2 To
samo, co wyrażenie1 wyrażenie2.

wyraż1 -o wyraż2
Or; wyrażenie2 nie jest oceniane, jeśli wyrażenie1 jest prawdziwe.

Dennis Williamson
źródło
Ach tak, zapomniałem o -o.
Ignacio Vazquez-Abrams
32

Jeśli nie ma znaczenia, że ​​cmd1 może uniemożliwić uruchomienie cmd2 z powodu kodu błędu 0:

find . -exec cmd1 \; -exec cmd2 \;

Jedynym niezawodnym sposobem, aby oba polecenia były zawsze uruchamiane, jest findwywołanie powłoki, która następnie uruchomi polecenia w kolejności:

find . -exec bash -c 'cmd1; cmd2' filedumper {} \;
Ignacio Vazquez-Abrams
źródło
2

Jeśli nie masz nic przeciwko tworzeniu skryptu wykonującego polecenia cmd1 i cmd2, to jest to po prostu:

find . -exec myscript {} \;

lub

find . -exec myscript {} +

Posługiwać się \; lub + w zależności od tego, czy myscript może obsługiwać więcej niż jeden plik na raz (robi się włochaty, jeśli w nazwach plików są spacje itp.).

Z mojego doświadczenia wynika, że ​​zapisywanie tego, co robiłeś w skrypcie, prawie zawsze było tego warte. Jeśli musisz to zrobić raz, musisz to zrobić ponownie.

Ale fajną sztuczką jest umieszczenie znaleziska w skrypcie:

if [ $# -gt 0 ]; then
    for each; do
        touch $each
    done
else
    find . -exec $0 {} +
fi

Następnie myscript działa na wszystkich plikach, które podajesz jako argumenty, ale jeśli nie podasz żadnych argumentów, uruchamia find z bieżącego katalogu, a następnie wywołuje się na znalezionych plikach. Pomija to fakt, że find -exec nie może wywoływać funkcji powłoki zdefiniowanych w skrypcie.

mza
źródło
0

Próbowałem obu poprzednich rozwiązań bez większego szczęścia. Ten działał dla mnie ładnie:

$ for i in `find . -exec echo {} \;`; do cmd1 $i; cmd2 $i; done
użytkownik9869932
źródło
To nie zadziała, jeśli lista plików jest zbyt duża.
Alex,
-3

spróbuj polecenie:

sudo find -name "*[!0-9][1-9].txt" -exec chmod 744 * {} \; -a -exec ls -l {} \; | sort | parallel ls -l
Saptak Das
źródło
4
Ech, to nie jest dobry pomysł. *W -execczęści wzrośnie do wszystkich plików w bieżącym katalogu. Zwłaszcza gdy działa jako sudo.
slhck