1

我正在使用这个命令来查找特定的文件(2 个文件),它们应该是独立的;

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

并返回正确的文件;

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

但是,如果我尝试将这些创建的文件制作成一个 tarball,它只包含-inamefind 命令的第一部分,就像这样;

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

所以它不包括*.pdf这个例子中的 s 并且只包括*.txts 在 tarball 中:

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

我该如何解决这个问题,以便将*.txts 和*.pdfs 都变成一个压缩包?

4

2 回答 2

4

首先,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

如果分支为真,则实际上什么都不,因为它仅以情况为条件。*.txtprintf*.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
于 2019-01-29T15:59:08.097 回答
1

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

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

find-print仅在根本没有指定操作时才添加隐式。没有括号,你有一个显式的-print0,它可以防止隐式-print应用于第一个-iname主的结果。

于 2019-01-29T15:59:54.750 回答