Zrozumienie opcji -exec find (1) (nawiasy klamrowe i znak plus)

17

Czy za pomocą następującego polecenia ktoś mógłby wyjaśnić, jaki jest cel kończących się nawiasów klamrowych ({}) i znaku plus (+)?

A w jaki sposób polecenie działałoby inaczej, gdyby zostały wykluczone z polecenia?

find . -type d -exec chmod 775 {} +
Ryan Prentiss
źródło

Odpowiedzi:

19

Nawiasy klamrowe zostaną zastąpione wynikami findpolecenia i chmodbędą uruchamiane na każdym z nich. Te +marki findpróbować uruchomić jak kilka komend jak to możliwe (tak, chmod 775 file1 file2 file3w przeciwieństwie do chmod 755 file1, chmod 755 file2, chmod 755 file3). Bez nich polecenie po prostu daje błąd. Wszystko to wyjaśniono w man find:

-exec command ;

      Wykonaj polecenie ; true, jeśli zwracany jest status 0. Wszystkie następujące argumenty findsą uważane za argumenty polecenia, dopóki nie ;zostanie napotkany argument składający się z „ ”. 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. …

-exec command {} +

      Ten wariant -execakcji uruchamia określone polecenie na wybranych plikach, ale linia poleceń jest budowana 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. …

terdon
źródło
12

Oprócz odpowiedzi terdona,

  • „Oczywiście” -exec …musi być zakończone średnikiem ( ;) lub znakiem plus ( +). Średnik jest szczególną postacią w skorupkach (lub, co najmniej, każdy Shell jaki kiedykolwiek używane), więc, jeśli ma być używany jako część findpolecenia , należy uciec lub cytowany ( \;, ";"lub ';').
  • Za -exec … ;pomocą {}ciąg może pojawić się dowolną liczbę razy w poleceniu, w tym zero lub dwa lub więcej w dowolnej pozycji.  Zobacz to na przykład, dlaczego możesz chcieć to zrobić -execbez użycia {}.   Posiadanie dwóch lub więcej występów jest przydatna przede wszystkim dlatego, że w (co najmniej) niektóre wersje findThe {}nie musi być słowo samo w sobie; może mieć inne postacie na początku lub na końcu; na przykład,

    find . -type f -exec mv {} {}.bak ";"
    

    Za pomocą -exec … +, {}ciąg musi pojawić się jako ostatni argument przed +. Polecenie jak

    find . -name "*.bak" -exec mv {} backup_folder +
    

    powoduje enigmatyczny find: missing argument to ‘-exec’komunikat o błędzie.

    • Obejściem tego, które jest specyficzne dla poleceń cpi mv, jest

      find . -name "*.bak" -exec mv -t backup_folder {} +
      

      lub

      find . -name "*.bak" -exec mv --target-directory=backup_folder {} +
      

    {}Musi być słowo samo w sobie; nie może mieć innych znaków na początku ani na końcu. I w (przynajmniej) niektórych wersjach findmożesz nie mieć więcej niż jedną {}.

  • Uwaga o zdrowiu psychicznym: Możesz powiedzieć

    odnaleźć . -name "* .sh" -type f -executable -exec {} opcjonalne argumenty tutaj ";"

    aby uruchomić każdy ze skryptów. Ale

    odnaleźć . -nazwa „* .sh” -type f -executable -exec {} +

    uruchamia jeden ze skryptów z nazwami wszystkich pozostałych jako parametrami. To jest podobne do powiedzenia

    ./*.sh
    

    jako polecenie powłoki, z wyjątkiem tego, findże nie gwarantuje, że posortuje wyniki, więc nie masz gwarancji, że uruchomisz aaa.sh (twój alfabetycznie pierwszy *.shplik) tak jak w przypadku uruchamiania ./*.sh.

  • Aspektem findtego może nie być całkowicie jasne dla początkujących jest to, że wiersz poleceń jest w rzeczywistości wykonywalną instrukcją w tajemnym języku. Na przykład,

    find . -name "*.sh" -type f -executable -print
    

    znaczy

    for each file
        if the file’s name matches `*.sh` (i.e., if it ends with `.sh`)
        then
            if it is a plain file (i.e., not a directory)
            then
                if it is executable (i.e., the appropriate `---x--x--x` bit is set)
                then
                    print the file’s name
                end if
            end if
        end if
    end loop
    

    lub po prostu,

    for each file
        if the file’s name matches `*.sh`  AND  it is a plain file  AND  it is executable
        then
            print the file’s name
        end if
    end loop
    

    Niektóre -słowa kluczowe są zarówno działaniem wykonywalnym, jak i testem. W szczególności dotyczy to -exec … ;; na przykład,

    find . -type f -exec grep -q cat {} ";" -print
    

    przetłumaczyć na

    dla każdego pliku
        jeśli jest to zwykły plik (tzn. nie katalog)
        następnie
            wykonaj grep -q nazwa pliku kota
            jeśli proces się powiedzie (tzn. zakończy się ze statusem 0)
            następnie
                wydrukuj nazwę pliku
            koniec jeśli
        koniec jeśli
    pętla końcowa

    który wypisze nazwy wszystkich plików zawierających ciąg „ cat”. I chociaż jest to coś, co grepmożna zrobić samodzielnie (z opcją -l(małe litery L)), przydatne może być użycie go finddo znalezienia plików zawierających określony ciąg ORAZ o określonym rozmiarze ORAZ należących do określonego właściciela AND zostały zmodyfikowane w określonym przedziale czasowym….

    To jednak nie działa -exec … +. Ponieważ -exec … +wykonuje jedno polecenie dla wielu plików, nie ma sensu używać go jako warunku logicznego w for each file …pętli.

  • Drugą stroną powyższego jest to, że findzazwyczaj kończy pracę ze statusem wyjścia 0, chyba że podasz nieprawidłowe argumenty lub napotka katalog, którego nie może odczytać. Nawet jeśli program, który wykonasz nie powiedzie się (zakończy działanie z niezerowym statusem wyjścia), findzakończy działanie ze statusem wyjścia równym 0.  Z wyjątkiem sytuacji,  gdy program, który wykonujesz z -exec … +błędem (zakończy działanie z niezerowym statusem wyjścia), findzakończy działanie z niezerowym statusem wyjścia.

Oprócz miliona wersji find(1) i testowania tego, co findfaktycznie działa na kilku systemach, specyfikacja Open Group Base Specification wydanie 7, 2013 zawiera niektóre informacje na temat tego find, co musi, może, a czego nie wolno robić.

G-Man mówi „Przywróć Monikę”
źródło
3
Uważaj, że przykładowe użycie ... -exec mv {} {}.bak ...nie gwarantuje poprawnego działania we wszystkich findimplementacjach. Standardowe stany POSIX {}muszą pojawiać się same, aby zawsze były rozpoznawane, w przeciwnym razie zachowanie może pozostawić znaki bez zmian lub zastąpić je nazwą ścieżki. W pierwszym przypadku całe polecenie spowoduje usunięcie wszystkich plików, ale ostatni z nich zostanie znaleziony ...
jlliagre