GNU查找“或”功能不适用于-print0 | xargs -0焦油

时间:2019-01-29 15:57:38

标签: shell unix gnu-findutils

我正在使用此命令查找可以单独使用的特定文件(2个文件);

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

并返回正确的文件;

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

但是,如果我尝试将这些已建立的文件制作为tarball,则它仅包含find命令的第一个-iname部分,就像这样;

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

因此在此示例中它不包含*.pdf,而在压缩包中仅包含*.txt

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

如何解决此问题,使*.txt*.pdf都成为压缩包?

2 个答案:

答案 0 :(得分:4)

首先,不建议使用find ... | xargs tar -c:当find生成文件列表的时间过长,以至于xargs分成多个tar调用时,除了最后一次调用将被覆盖。

仅运行tar的一个副本,并配置那个以便从stdin读取文件要安全得多:

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

编写与您的find逻辑等效的shell,原始/原始版本可能如下所示:

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

如果*.txt分支为true,则实际上没有完成 ,因为printf仅以*.pdf情况为条件。


使用括号将您的分支分组:

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

答案 1 :(得分:1)

-o的优先级低于连接-a-iname '*.pdf'的隐式-print0的优先级。您需要在-o的括号中加上括号:

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

find仅在根本没有指定 操作的情况下才添加隐式-print。如果没有括号,则有一个显式-print0,可以防止将隐式-print应用于第一个-iname主变量的结果。