Czy istnieje sposób na logiczne połączenie dwóch poleceń powłoki, które są wywoływane przez find - exec ?
Na przykład, aby wydrukować wszystkie pliki .csv , które zawierają ciąg foo wraz z jego wystąpieniem, chciałbym zrobić:
find . -iname \*.csv -exec grep foo {} && echo {} \;
ale bash narzeka na „brakujący argument na„ -exec ””
-exec
w sekwencji lub użyć jednego-exec sh -c 'grep foo "$0" && printf %s\\n "$0"' {} \;
.sh
(w tym przypadku{}
) będzie$1
i$0
będzie podobnysh
. Ale w rzeczywistości masz rację, pierwszy argument pojawia się jako$0
. Posiadanie pierwszego argumentu jako nazwy polecenia wywołującego jest tylko konwencją, która w takich przypadkach nie jest automatycznie egzekwowana.Odpowiedzi:
-exec
jest predykatem, który uruchamia polecenie (nie powłokę) i zwraca wartość true lub false na podstawie wyniku polecenia (zero lub niezerowy status wyjścia).Więc:
by wydrukować ścieżkę do pliku, czy
grep
znaleziska foo w pliku. Zamiast tego-print
możesz użyć innego-exec
predykatu lub dowolnego innego predykatuZobacz także
!
i-o
znajdź operatory negacji i lub .Alternatywnie możesz uruchomić powłokę jako:
Lub, aby uniknąć konieczności uruchamiania powłoki dla każdego pliku:
źródło
Problem, przed którym stoisz, polega na tym, że powłoka najpierw analizuje wiersz poleceń i widzi dwa proste polecenia oddzielone przez
&&
operatora:find . -iname \*.csv -exec grep foo {}
iecho {} \;
. Cytując&&
(find . -iname \*.csv -exec grep foo {} '&&' echo {} \;
) omija, ale teraz komenda wykonywana przezfind
to cośgrep
z argumentamifoo
,wibble.csv
,&&
,echo
iwibble.csv
. Musisz poinstruować,find
aby uruchomić powłokę, która zinterpretuje&&
operatora:Zauważ, że pierwszy argument po
sh -c SOMECOMMAND
to$0
, nie$1
.Możesz zaoszczędzić czas uruchamiania procesu powłoki dla każdego pliku, grupując wywołania poleceń
-exec … +
. Aby ułatwić przetwarzanie, podaj pewną wartość zastępczą,$0
aby"$@"
wyliczała nazwy plików.Jeśli polecenie powłoki dzieli tylko dwa programy
&&
,find
może wykonać zadanie samodzielnie: napisz dwie kolejne-exec
akcje, a druga zostanie wykonana tylko wtedy, gdy pierwsza zakończy pracę ze statusem 0.(Zakładam, że
grep
iecho
są tylko w celach ilustracyjnych, ponieważ-exec echo
można je zastąpić,-print
a wynikowy wynik i tak nie jest szczególnie użyteczny.)źródło
./some-file: grep: command not found
komunikat o błędzie.-exec find sh -c '... "$1"' sh {} \;
nie miałbym problemu. W drugim poleceniu find znajduje się literówka (związana).W tym konkretnym przypadku zrobiłbym:
find . -iname \*.csv -exec grep -l foo \{\} \;
Lub jeśli masz ACK :
ack -al -G '.*\.csv' foo
Aby odpowiedzieć na twoje aktualne pytanie, coś takiego może działać:
find . -iname \*.csv -exec sh -c "grep foo {} && echo {}" \;
źródło