find: brakujący argument dla -exec

206

Pomogło mi dzisiaj polecenie, ale wydaje się, że nie działa. To jest polecenie:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 && rm {}\;

Powłoka powraca

find: missing argument to `-exec'

W zasadzie próbuję to zrobić, przeglądając katalog rekurencyjnie (jeśli ma inne katalogi) i uruchamiając komendę ffmpeg na .rmtypach plików i konwertując je na .mp3typy plików. Po zakończeniu usuń .rmwłaśnie przekonwertowany plik.

Doceniam wszelką pomoc w tym zakresie.

Abs
źródło

Odpowiedzi:

340

-execKomenda musi zostać zakończona ;(tak zwykle trzeba wpisać \;lub ';'w celu uniknięcia interpretion przez powłokę) lub +. Różnica polega na tym ;, że z , polecenie jest wywoływane raz na plik, z +, jest wywoływane tak mało razy, jak to możliwe (zwykle raz, ale linia poleceń ma maksymalną długość, więc można ją podzielić) ze wszystkimi nazwami plików . Zobacz ten przykład:

$ cat /tmp/echoargs
#!/bin/sh
echo $1 - $2 - $3
$ find /tmp/foo -exec /tmp/echoargs {} \;
/tmp/foo - -
/tmp/foo/one - -
/tmp/foo/two - -
$ find /tmp/foo -exec /tmp/echoargs {} +
/tmp/foo - /tmp/foo/one - /tmp/foo/two

Twoje polecenie ma dwa błędy:

Po pierwsze, używasz {};, ale ;musi być własnym parametrem.

Po drugie, polecenie kończy się na &&. Podałeś „uruchom find, a jeśli to się powiedzie, usuń plik o nazwie {};.”. Jeśli chcesz użyć powłoki w -execpoleceniu, musisz jawnie uruchomić ją w powłoce, takiej jak -exec sh -c 'ffmpeg ... && rm'.

Jednak nie należy dodawać {} wewnątrz polecenia bash, spowoduje to problemy, gdy będą znaki specjalne. Zamiast tego możesz przekazać dodatkowe parametry do powłoki po -c command_string(patrz man sh):

$ ls
$(echo damn.)
$ find * -exec sh -c 'echo "{}"' \;
damn.
$ find * -exec sh -c 'echo "$1"' - {} \;
$(echo damn.)

Widzisz, że $rzecz jest oceniana przez powłokę w pierwszym przykładzie. Wyobraź sobie, że istnieje plik o nazwie $(rm -rf /):-)

(Uwaga dodatkowa: Nie -jest potrzebna, ale pierwsza zmienna po poleceniu jest przypisana do zmiennej $0, która jest specjalną zmienną zwykle zawierającą nazwę uruchamianego programu i ustawienie tego parametru na parametr jest trochę nieczyste, chociaż wygrało prawdopodobnie nie zaszkodzi tutaj, więc ustawiliśmy to na -początek i zaczynamy od $1).

Więc twoje polecenie może być podobne

find -exec bash -c 'ffmpeg -i "$1" -sameq "$1".mp3 && rm "$1".mp3' - {} \;

Ale jest lepszy sposób. znajdź wsparcie andi or, więc możesz robić rzeczy takie jak find -name foo -or -name bar. Ale to również działa z -exec, co daje wartość true, jeśli polecenie zakończy się pomyślnie, i false, jeśli nie. Zobacz ten przykład:

$ ls
false  true
$ find * -exec {} \; -and -print
true

Uruchamia druk tylko wtedy, gdy polecenie zakończyło się powodzeniem, trueale nie dla false.

Możesz więc użyć dwóch instrukcji exec połączonych łańcuchem z -and, i wykona to drugie, tylko jeśli pierwsza zostanie pomyślnie uruchomiona.

Marian
źródło
3
Kluczem wydaje się być wiersz Mariana „sam jest argumentem”, czyli to, co zrobiłem dla mnie, jeśli chodzi o żarówkę i dla mojego kodu próbki. dzięki.
pjammer
3
To najlepszy opis, który przeczytałem na -exec. Jest niezwykle potężny, ale zawsze trudno mi uzyskać odpowiednią składnię. To sprawiło, że kilka rzeczy stało się bardziej przejrzystych. Szczególnie zawijanie polecenia w osobną powłokę. Miły. Dzięki.
Eurospoofer
3
Należy pamiętać, że -andi -ornie są przenośne. POSIX określa -ai-o faktycznie -ajest zawsze zakładany (stąd nie jest potrzebny).
gniourf_gniourf
Ponadto przed terminatorem musi być spacja. Ex "\;"nie działa, ale " \;"działa
frmdstryr
56

Teraz to rozgryzłem. Kiedy musisz uruchomić dwie komendy w exec w znalezieniu, musisz mieć dwa osobne exec. To w końcu zadziałało dla mnie.

find . -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 \; -exec rm {} \;
Abs
źródło
Nie wiesz, czy dostanie zmienną pliku do usunięcia? Czy ktoś wie, czy tak jest?
Abs
7
Aby przetestować takie rzeczy, po prostu dodaj echoprzed poleceniami i zobacz, co robi.
Marian
2
@Marian, echojest dość niewiarygodny - nie można odróżnić między echo "one argument"i echo one argument(wynik tego ostatniego jest fałszywy, ponieważ w rzeczywistości przekazuje echodwa całkowicie odrębne argumenty). Znacznie lepiej zrobić coś takiego -exec bash -c 'printf "%q " "$@"' _ ffmpeg -i {} -sameq {}.mp3 \; -printf '\n', co wydrukuje wydruk w taki sposób, aby znaki niedrukowalne były widoczne, dzięki czemu można wykryć znaki nowej linii DOS i inne dziwności.
Charles Duffy,
52

Spróbuj wstawić spację przed każdym \;

Pracuje:

find . -name "*.log" -exec echo {} \;

Nie działa:

find . -name "*.log" -exec echo {}\;
Dustin Cowles
źródło
1
Często mnie to podnieca. Któregoś dnia domyślnie dodam spację.
harperville
Dla mnie działa odwrotnie w Cygwin pod Windows 7: bez spacji przed \; działa, z przestrzenią - nie. Ale jeśli usunę \, ze spacją wcześniej; działa i bez wcześniejszej przestrzeni; tak nie jest, tak jak tu opisano.
WebComer,
7

Tylko dla twojej informacji:
Właśnie próbowałem użyć polecenia „find -exec” w systemie Cygwin (UNIX emulowanym w systemie Windows) i wydaje się, że ukośnik odwrotny przed średnikiem należy usunąć:
find ./ -name "blabla" -exec wc -l {} ;

Dominique
źródło
Naprawdę się zmieszałem. find /etc/nginx -name '*.conf' -exec echo {} ;i find /etc/nginx -name '*.conf' -exec echo {}\;dał ten sam wynik. :(
Kirby
Używam powłoki Bash, która jest dostarczana z Git dla Windows, a odpowiedź Dustina Cowlesa działa dla mnie. Innymi słowy: bez cudzysłowów, odwrotny ukośnik ze znakiem średnika, spacja po {}.
mamacdon
Nie ma różnicy w znaczeniu, ale w niektórych przypadkach musisz umieścić odwrotny ukośnik, w niektórych przypadkach nie możesz go umieścić, a w innych przypadkach możesz wybrać.
Dominique,
2

Na wypadek, gdyby ktoś widział podobne „brakujące argumenty -exec” w skryptach bash Amazon Opsworks Chef, musiałem dodać kolejny ukośnik odwrotny, aby uciec przed \;

bash 'remove_wars' do
  user 'ubuntu'
  cwd '/'
  code <<-EOH
    find /home/ubuntu/wars -type f -name "*.war" -exec rm {} \\;
  EOH
  ignore_failure true
end
John Cooper
źródło
2

Ponadto, jeśli ktoś inny ma argument „find: missing argument -exec”, może to pomóc:

W niektórych powłokach nie musisz uciekać, tzn. Nie potrzebujesz „\” przed „;”.

find <file path> -name "myFile.*" -exec rm - f {} ;
sprzedawca
źródło
2
;Nie są notowane lub uciekł tutaj oznacza, że mogą być spożywane przez powłokę, nie czytana przez find. Ponadto, -fi - fsą dwie różne rzeczy.
Charles Duffy,
1

Myślę, że musisz uciec.

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i {} \-sameq {}.mp3 \&\& rm {}\;
Matthew Smith
źródło
0

Zarówno {}, jak i && będą powodować problemy z powodu rozszerzenia przez wiersz poleceń. Proponuję spróbować:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i \{} -sameq \{}.mp3 \; -exec rm \{} \;
VeeArr
źródło
Jeśli pierwsze polecenie w exec powiedzie się, a drugie polecenie w exec zostanie wykonane, czy nadal będzie miało dostęp do {}zmiennej umożliwiającej usunięcie odpowiedniego pliku?
Abs
Do czego się {}rozwija? Chyba że zawiera dwie kropki lub przecinki, które pozostaną bez zmian.
Marian
0

Musisz umieścić spację między {}i\;

Więc polecenie będzie wyglądało tak:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 && rm {} \;
Azafo Cossa
źródło
-4

Jeśli nadal pojawia się komunikat „find: missing argument to -exec”, spróbuj zawrzeć argument wykonania w cudzysłowach.

find <file path> -type f -exec "chmod 664 {} \;"
zabiegać
źródło