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 '{}' \+

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 {} \;

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.


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ą.


(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 {} \;


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


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.