`find` z wieloma` -name` i `-exec` wykonuje tylko ostatnie dopasowania` -name`

74

Kiedy używam

find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"

znajdzie wszystkie typy plików. Ale kiedy dodam -execna końcu:

find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt" -exec sh -c 'echo "$0"' {} \;

wygląda na to, że drukuje tylko .txtpliki. Co ja robię źle?

Uwaga: za pomocą MINGW (Git Bash)

jakub.g
źródło
Wskazówka: pierwsze polecenie wyświetli również katalogi, których nazwy pasują *.js*lub *.txt.
Wildcard

Odpowiedzi:

99
odnaleźć . -type f -name "* .htm *" -o -name "* .js *" -o -name "* .txt"

jest skrótem od:

odnaleźć . \ (\ ( -type f -a -name "* .htm *" \) -o \
          \ ( -name "* .js *" \) -o \
          \ ( -name "* .txt" \) \
       \) -drukarka

Oznacza to, że ponieważ nie określono predykatu akcji (tylko warunki ), -printakcja jest domyślnie dodawana dla plików spełniających warunki.

(a przy okazji, wydrukowałoby to .jspliki nieregularne ( -type fdotyczy to tylko .htmplików)).

Podczas:

odnaleźć . -type f -name "* .htm *" -o -name "* .js *" -o -name "* .txt" \
  -exec sh -c 'echo "$ 0"' {} \;

jest skrótem od:

odnaleźć . \ ( -type f -a -name "* .htm *" \) -o \
       \ ( -name "* .js *" \) -o \
       \ ( -name "* .txt" -a -exec sh -c 'echo "$ 0"' {} \; \)

Dla find(jak w wielu językach) AND ( -a; domyślny, gdy pominięty) ma pierwszeństwo przed OR ( -o), a dodanie jawnego predykatu akcji (tutaj -exec) anuluje -printniejawną akcję widoczną powyżej. Tutaj chcesz:

find . -type f \( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" \) \
  -exec sh -c 'echo "$0"' {} \;

Lub:

find . -type f \( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" \) -exec sh -c '
   for i do
     echo "$i"
   done' sh {} +

Aby uniknąć uruchamiania jednego shpliku na plik.

Stéphane Chazelas
źródło
W niektórych zastosowaniach sh -c musisz dodać zerowy argument dla sh (chociaż w innych już go umieściłeś).
James Youngman
1
To świetna odpowiedź!
Marinos An
30

To implikowane nawiasy klamrowe. Dodaj wyraźne nawiasy klamrowe.\( \)

find . -type f \( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" \) -exec sh -c 'echo "$0"' {} \;

lub używając xargs (lubię xargs, uważam, że jest to łatwiejsze, ale najwyraźniej nie tak przenośne).

find . -type f \( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" \) -print0 | xargs -0 -n1 echo
ctrl-alt-delor
źródło