find: brakujący argument dla -exec

18

Próbuję uruchomić następujące polecenie:

find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' +

To zwraca błąd:

find: missing argument to -exec

Nie widzę, co jest nie tak z tym poleceniem, ponieważ wydaje się pasować do strony podręcznika:

-exec polecenie {} +

Ten wariant opcji -exec uruchamia określone polecenie na wybranych plikach, ale wiersz poleceń jest budowany przez dołączenie każdej wybranej nazwy pliku na końcu; całkowita liczba wywołań polecenia będzie znacznie mniejsza niż liczba dopasowanych plików. Linia poleceń jest budowana w taki sam sposób, jak xargs buduje swoje linie poleceń. W poleceniu dozwolona jest tylko jedna instancja „{}”. Polecenie jest wykonywane w katalogu startowym.

Próbowałem też:

find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar {} +
find a/folder b/folder -name *.c -o -name *.h -exec 'grep -I foobar' {} +
find a/folder b/folder -name *.c -o -name *.h -exec 'grep -I foobar' '{}' +
find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar '{}' +
find a/folder b/folder \( -name *.c -o -name *.h \) -exec grep -I foobar '{}' +
find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+
David Kennedy
źródło
Czy próbowałeś uciec +na końcu? find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+
jayhendren
3
Być może korzystasz ze starej wersji GNU find. Chociaż -exec cmd {} +wariant jest POSIX i był dostępny od lat 80., GNU znalazł go (stosunkowo) dopiero niedawno (2005). Co find --versionci mówi
Stéphane Chazelas
2
@Koveras, to by było na tyle. -exec {} +został dodany w 4.2.12 w 2005 r. W starszych znaleziskach GNU możesz użyć (nie POSIX), -print0 | xargs -r0aby uzyskać coś podobnego. 4.1pochodzi z 1994 r.
Stéphane Chazelas
1
JRFerguson wskazał (w odpowiedzi, który został usunięty), że -nameargumenty wzorca powinny być podane: -name "*.c" -o -name "*.h". To prawda, chociaż nie ma to związku z -execbłędem. Zauważysz, że wszystkie pozostałe odpowiedzi umieszczają symbole wieloznaczne w cudzysłowie, chociaż tylko Gilles o tym wspomina. … (Ciąg dalszy)
G-Man mówi „
1
(Ciąg dalszy)… odpowiedź jlliagre zrzuca wyrażenie nazwy -name "*.[ch]"bez wyjaśnienia. Ma to tę zaletę, że upraszcza wiersz poleceń, a w szczególności eliminuje  -o. Znajdź wyrażenia wymagające -osą trudne do znalezienia . Twoje jest złe; jeśli twoje polecenie zostanie naprawione, aby nie było błędu (jak w odpowiedzi Gillesa), będzie działać greptylko na .hplikach. Musisz to zrobić '(' -name '*.c' -o -name '*.h' ')'.
G-Man mówi „Przywróć Monikę”

Odpowiedzi:

18

Musisz usunąć pojedyncze cytaty, których używasz w pobliżu {}. Polecenie można uprościć w następujący sposób:

find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} +

Jeśli używasz archaicznej wersji GNU find, powinna ona nadal działać:

find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} \;
jlliagre
źródło
Ups, miały być cytatami, a nie odwrotnymi.
David Kennedy
Cytaty byłyby bezużyteczne, ponieważ {}nie miałyby żadnego konkretnego znaczenia dla powłoki.
jlliagre
Ze stron podręcznika find: ciąg „{}” jest zastępowany bieżącą nazwą pliku przetwarzaną wszędzie tam, gdzie występuje w argumentach polecenia, a nie tylko w argumentach, w których jest on sam, jak w niektórych wersjach find. Oba te konstrukcje mogą wymagać ucieczki („\”) lub cytowania, aby chronić je przed rozszerzeniem przez powłokę. ”
David Kennedy
1
Rzeczywiście przeczytałem to na stronie podręcznika, ale faktem jest, że nie znam powłoki, która wymaga cytowania nawiasów klamrowych. Jakiej powłoki używasz?
jlliagre
grzmotnąć. Z cytatami lub bez nich i tak otrzymuję błąd.
David Kennedy
10

„Brak argumentu do -exec” zwykle oznacza, że ​​argument do - execnie ma terminatora. Terminator musi być argumentem zawierającym tylko znak ;(który musi być cytowany w poleceniu powłoki, więc zwykle jest zapisany \;lub';' ), lub dwoma kolejnymi argumentami zawierającymi {}i +.

Stephane Chazelas stwierdził , że używasz starszej wersji GNU find, która nie obsługuje -exec … {} +, tylko -exec {} \;. Chociaż GNU spóźnił się z przyjęciem -exec … {} +, polecam, abyś dostał mniej zabytkowy zestaw narzędzi (taki jak Cygwin , który zawiera git i wiele więcej, lub GNUwin32 , który nie ma git, ale nie ma złych pracowników) -to-use-linux-but-we-impose-windows klimat, który daje Cygwin). Ta funkcja została dodana w wersji 4.2.12, ponad 9 lat temu (była to ostatnia zidentyfikowana funkcja, która pozwoliła uzyskać findzgodność z GNU POSIX).

Jeśli chcesz pozostać przy starszym znalezisku GNU, możesz użyć -print0z, xargs -0aby uzyskać podobną funkcjonalność: grupowe wykonywanie poleceń, obsługa dowolnych nazw plików.

find a/folder b/folder -name '*.c' -o -name '*.h' -print0 | xargs -0 grep -I foobar /dev/null

Zawsze cytuj symbole wieloznaczne w findwierszu polecenia. W przeciwnym razie, jeśli zdarzy się, że uruchomisz to polecenie z katalogu zawierającego .cpliki, niecytowany *.czostanie rozwinięty do listy .cplików w bieżącym katalogu.

Dodanie /dev/nulldo grepwiersza poleceń jest sztuczką, aby upewnić się, że grep zawsze wydrukuje nazwę pliku, nawet jeśli findzdarzy się znalezienie pojedynczego dopasowania. W przypadku GNU find inną metodą jest przekazanie opcji -H.

Gilles „SO- przestań być zły”
źródło
1
Co masz na myśli mówiąc, że cygwin daje atmosferę złych pracowników próbujących używać systemu Linux, ale nakładamy okna?
David Kennedy
GNUwin32 nie oczekuje :(
David Kennedy
Zobacz moje komentarze do pytania.
G-Man mówi „Reinstate Monica”
Cytaty wokół pół działały z poziomu skryptu package.json.
bvj
2

Jeśli polecenie takie jak

find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar {} +

zwraca błąd

find: missing argument to -exec

prawdopodobną przyczyną jest zbyt stary GNU, findktóry nie obsługuje składni -exec mycommand {} +. W takim przypadku należy uruchomić wymianę o niskiej wydajności, -exec mycommand {} \;która uruchomi jeden mycommandraz dla każdego znalezionego celu zamiast zbierać wiele celów i uruchamiaćmycommand tylko raz.

Jednak GNU findnie obsługuje np

find . -type f -and -name "*.ttf" -exec cp {} ~/.fonts +

ponieważ GNU findobsługuje tylko kombinację dosłowną {} +zamiast bardziej ogólnej {} additional parameters +. Zauważ, że między nawiasami klamrowymi a +postacią nie może być niczego . Jeśli spróbujesz tego, otrzymasz ten sam błąd:

find: missing argument to -exec

Obejściem tego problemu jest użycie składni, {} additional parameters \;która działa, ale wykona polecenie raz dla każdego znalezionego celu. Jeśli potrzebujesz większej wydajności w GNU find, musisz napisać skrypt otoki, który może dołączyć dodatkowe parametry do podanych argumentów. Coś jak

#!/bin/bash
exec mycommand "$@" additional parameters

powinno być wystarczająco dobre. Lub, jeśli nie chcesz tworzyć pliku tymczasowego, możesz użyć liniowania, aby zmienić kolejność parametrów w ten sposób:

find . -type f -and -name "*.ttf" -exec bash -c 'mycommand "$@" extra arguments' {} +

który zostanie wykonany mycommand {list of ttf files} extra arguments. Pamiętaj, że może być konieczne dwukrotne ucieczkę znaków specjalnych do uderzenia za -cflagą.

Mikko Rantalainen
źródło
(1) Część powyższa, która faktycznie odpowiada na pytanie, została już podana przez inne osoby. (2) To, co opisujesz, nie jest wadą ani brakiem GNU find, ale poprawnym zachowaniem określonym przez POSIX .
G-Man mówi „Reinstate Monica”
1
+1 Wreszcie ktoś, kto odpowiada, dlaczego dodatkowe parametry nie działają! Wydaje się, że jest to niedobór definicji POSIX.
Jonathan
Jeśli masz GNU find, prawdopodobnie masz GNU cp. W takim przypadku możesz find ... -exec cp --target-directory ~/.fonts {} +zachować {}koniec na końcu łańcucha wykonawczego.
roaima,
1

find . -type f -perm 0777 -exec chmod 644 {}\;

dostał błąd find: missing argument to ``-exec'.

Dodanie spacji {}i \naprawiono:

find . -type f -perm 0777 -print -exec chmod 644 {} \;

ShreePool
źródło
1
W findpoleceniu w danym pytaniu nie ma takiego problemu .
Kusalananda
W pytaniu nie jest w porządku, że zrozumiałem, ale problem jest taki sam „znajdź: brakujący argument do opcji„ -eksport ”, problem może wystąpić z innej przyczyny, odpowiedziałem, ponieważ widziałem tę samą instrukcję problemu.
ShreePool,
@ Kuusalananda, dobry żal, noob dostarczył rozwiązanie zgłoszonego błędu, który został podany przez PO zarówno w tytule, jak i w treści pytania.
bvj
@bvj Pytanie wyraźnie dotyczy +formy -execopcji find. Ta odpowiedź rozwiązuje problem, którego nie ma użytkownik zadający pytanie.
Kusalananda
-1

W przeszłości miałem ból głowy ze składnią exec. przez większość dni wolę ładniejszą składnię bash:

for f in `find a/folder b/folder -name "*.[ch]"`; do grep -I foobar $f; done

Ma pewne ograniczenia, gdy chcesz traktować pliki jako grupę, ponieważ każdy jest oceniany szeregowo, ale możesz dobrze wyprowadzić wyniki gdzie indziej

tolster710
źródło
1
Chociaż zwykle działa, jest znacznie mniej użyteczny niż wersja czysto znajdująca, ponieważ nie może poprawnie obsługiwać plików z białymi spacjami w nazwie.
Etan Reisner
5
Nie rób tego. To się zrywa, gdy tylko pliki zawierają spacje i inne „dziwne” znaki. Jest to również bardziej złożone i wolniejsze niż find … -exec … \;, więc nie ma powodu, aby z tego korzystać, nawet jeśli wiesz, że twoje nazwy plików są oswojone.
Gilles „SO- przestań być zły”
było to pomocne w mojej sytuacji, w której musiałem uruchomić wiele linii logiki na podstawie nazw plików (takich jak usuwanie znaków, tworzenie katalogów, a następnie przenoszenie plików). Próbowanie znalezienia robienia wielu rzeczy w jednym execbyło zbyt wielkim bólem głowy przez 5 minut, które chciałem na to poświęcić. Moje nazwy plików były oswojone i to rozwiązało mój problem :)
gMale