TL; DR: Jeśli jesteś tutaj, aby uzyskać najbardziej poprawną odpowiedź, prawdopodobnie chcesz moich osobistych preferencji find . -name '*.txt' -exec process {} \;
(patrz na dole tego postu). Jeśli masz czas, przeczytaj resztę, aby zobaczyć kilka różnych sposobów i problemów z większością z nich.
Pełna odpowiedź:
Najlepszy sposób zależy od tego, co chcesz zrobić, ale oto kilka opcji. Tak długo, jak żaden plik lub folder w poddrzewie nie ma spacji w nazwie, możesz po prostu zapętlić pliki:
for i in $x; do # Not recommended, will break on whitespace
process "$i"
done
Lepiej marginalnie, wytnij zmienną tymczasową x
:
for i in $(find -name \*.txt); do # Not recommended, will break on whitespace
process "$i"
done
O wiele lepiej jest globować, kiedy możesz. Bezpieczny spacja dla plików w bieżącym katalogu:
for i in *.txt; do # Whitespace-safe but not recursive.
process "$i"
done
Włączając tę globstar
opcję, możesz globować wszystkie pasujące pliki w tym katalogu i we wszystkich podkatalogach:
# Make sure globstar is enabled
shopt -s globstar
for i in **/*.txt; do # Whitespace-safe and recursive
process "$i"
done
W niektórych przypadkach, np. Jeśli nazwy plików są już w pliku, może być konieczne użycie read
:
# IFS= makes sure it doesn't trim leading and trailing whitespace
# -r prevents interpretation of \ escapes.
while IFS= read -r line; do # Whitespace-safe EXCEPT newlines
process "$line"
done < filename
read
może być bezpiecznie używany w połączeniu z find
poprzez odpowiednie ustawienie ogranicznika:
find . -name '*.txt' -print0 |
while IFS= read -r -d '' line; do
process "$line"
done
W przypadku bardziej skomplikowanych wyszukiwań prawdopodobnie będziesz chciał użyć find
tej -exec
opcji lub z -print0 | xargs -0
:
# execute `process` once for each file
find . -name \*.txt -exec process {} \;
# execute `process` once with all the files as arguments*:
find . -name \*.txt -exec process {} +
# using xargs*
find . -name \*.txt -print0 | xargs -0 process
# using xargs with arguments after each filename (implies one run per filename)
find . -name \*.txt -print0 | xargs -0 -I{} process {} argument
find
może także cd do katalogu każdego pliku przed uruchomieniem polecenia za pomocą -execdir
zamiast -exec
, i może być interaktywny (monit przed uruchomieniem polecenia dla każdego pliku) za pomocą -ok
zamiast -exec
(lub -okdir
zamiast -execdir
).
*: Technicznie zarówno find
i xargs
(domyślnie) uruchomią polecenie z tyloma argumentami, ile mogą zmieścić się w wierszu poleceń, tyle razy, ile potrzeba, aby przejść przez wszystkie pliki. W praktyce, chyba że masz bardzo dużą liczbę plików, nie będzie to miało znaczenia, a jeśli przekroczysz długość, ale potrzebujesz ich wszystkich w tym samym wierszu poleceń, SOL znajdzie inną drogę.