GNU find "or" 函数不适用于 -print0 | xargs -0 tar

GNU find "or" function is not working with -print0 | xargs -0 tar

我正在使用此命令查找特定文件(2 个文件),这些文件应该可以独立运行;

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

和returns正确的文件;

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

但是,如果我尝试将这些创建的文件制作成压缩包,它只包含 find 命令的第一个 -iname 部分,如下所示;

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

所以它不包含此示例中的 *.pdfs,并且仅包含压缩包中的 *.txts:

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

我该如何解决这个问题,使 *.txts 和 *.pdfs 都成为一个 tarball?

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

运行 更安全,只有一份 tar,并配置 that 从标准输入读取:

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

编写等同于您的 find 逻辑的 shell,original/buggy 版本可能如下所示:

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

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


使用括号对分支进行分组:

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

...这使得逻辑看起来像:

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

或者在每边放置一个单独的动作副本:

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

...这就像:

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

-o 的优先级低于连接 -iname '*.pdf'-print0 的隐式 -a。您需要将参数括起来 -o:

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

find 如果根本没有指定 操作,则只添加隐式 -print。没有括号,你有一个显式的 -print0,它可以防止将隐式的 -print 应用于第一个 -iname primary.

的结果。