Функция GNU find "or" не работает с -print0 |xargs -0 tar - PullRequest
0 голосов
/ 29 января 2019

Я использую эту команду, чтобы найти конкретные файлы (2 файла), которые работают так, как и должно быть самостоятельно;

find . -iname '*.txt' -o -iname '*.pdf'

и возвращает правильные файлы;

./.folder1/file1.txt
./.folder1/file1.pdf
./.folder2/file2.txt
./.folder2/file2.pdf

Однако, если я попытаюсь превратить эти основанные файлы в тарбол, он будет включать только первую -iname часть из команды поиска, например,

find . -iname '*.txt' -o -iname '*.pdf' -print0 | xargs -0 tar -czvf files.tar.gz

, поэтому он не включает *.pdf s в этом примере и включает только *.txt s в архиве:

./.folder1/file1.txt
./.folder2/file2.txt

как я могу это исправить, чтобы он превратил *.txt s и *.pdf s в тарбол?

Ответы [ 2 ]

0 голосов
/ 29 января 2019

-o имеет более низкий приоритет, чем неявное -a, которое объединяет -iname '*.pdf' и -print0.Вам необходимо заключить аргументы в скобки, чтобы -o:

find . \( -iname '*.txt' -o -iname '*.pdf' \) -print0

find добавляет неявное -print, только если нет действий, указанных вообще.Без скобок у вас есть явный -print0, который предотвращает применение неявного -print к результату первого -iname первичного.

0 голосов
/ 29 января 2019

Во-первых, использование find ... | xargs tar -c не рекомендуется: если find генерирует список файлов настолько долго, что xargs разделяется на несколько tar вызовов, все, кроме последнего, будут перезаписаны.

Намного безопаснее запустить только одну копию tar и настроить , чтобы читать со стандартного ввода:

find . '(' -iname '*.txt' -o -iname '*.pdf' ')' -print0 |
  tar -c --null -T - -zf backups.tar.gz

Написание оболочки, эквивалентной findлогика, оригинальная / ошибочная версия может выглядеть следующим образом:

for f in *; do
  { [[ $f = *.txt ]]; } || \
  { [[ $f = *.pdf ]] && printf '%s\0' "$f"; }
done

На самом деле ничего нет сделано , если ветвь *.txt истинна, потому что printf зависит только от*.pdf case.


Либо используйте скобки, чтобы сгруппировать ваши ветви:

find . '(' -iname '*.txt' -o -iname '*.pdf' ')' -print0

... что делает логику похожей на:

for f in *; do
  { [[ $f = *.txt ]] || [[ $f = *.pdf ]]; } && printf '%s\0' "$f";
done

Или поместите отдельную копию действия с каждой стороны:

find . -iname '*.txt' -print0 -o -iname '*.pdf' -print0

..., которая действует как:

for f in *; do
  { [[ $f = *.txt ]] && printf '%s\0' "$f"; } || \
  { [[ $f = *.pdf ]] && printf '%s\0' "$f"; }
done
...