当文件名包含空格时如何使用 find?

当文件名包含空格时如何使用 find?

我想将文件名通过管道传递给其他程序,但当名称包含空格时,它们都会窒息。

假设我有一个名为的文件。

foo bar

我怎样才能find返回正确的名称?

显然我想要:

foo\ bar

或者:

"foo bar"

编辑:我不想经历xargs,我想得到一个格式正确的字符串,find以便我可以将文件名字符串直接通过管道传输到另一个程序。

答案1

正面:

find . -type f -exec sh -c '
  for f do
    : command "$f"
  done
' sh {} +

find支持-print0xargs支持-0

find . -type f -print0 | xargs -0 <command>

-0选项告诉 xargs 使用 ASCII NUL 字符而不是空格来结束(分隔)文件名。

例子:

find . -maxdepth 1 -type f -print0 | xargs -0 ls -l

答案2

使用-print0是一种选择,但并非所有程序都支持使用空字节分隔的数据流,因此您必须在某些情况下使用xargs-0选项,正如 Gnouc 的回答所述。

另一种选择是使用find's-exec-execdiroptions。以下第一个将somecommand一次提供一个文件名,而第二个将扩展为文件列表:

find . -type f -exec somecommand '{}' \;
find . -type f -exec somecommand '{}' +

您可能会发现在许多情况下使用通配符会更好。如果您有现代 shell(bash 4+、zsh、ksh),则可以使用globstar( **) 进行递归通配。在 bash 中,你必须这样设置:

shopt -s globstar
somecommand ./**/*.txt ## feeds all *.txt files to somecommand, recursively

我的 .bashrc 中有一行内容shopt -s globstar extglob,因此它始终对我启用(扩展的 glob 也是如此,这也很有用)。

如果您不想要递归性,显然只需使用./*.txt工作目录中的每个 *.txt 即可。find具有一些非常有用的细粒度搜索功能,并且对于数以万计的文件是必需的(此时您将遇到 shell 的最大参数数量),但对于日常使用来说,它通常是不必要的。

答案3

因此,如果您不想使用xargs(因此可能也不想使用parallel),find可以按以下方式逐行读取和处理输出:

find . -type f | while read x; do
  # do something with $x
done

答案4

就我个人而言,我会使用-execfind 操作来解决此类问题。或者,如果需要,xargs允许并行执行。

然而,有一种方法可以find生成 bash 可读的文件名列表。毫不奇怪,它使用-execand bash,特别是命令的扩展printf

find ... -exec bash -c 'printf "%q " "$@"' printf {} ';'

然而,虽然这会正确打印出 shell 转义的单词,但它不能与 一起使用$(...),因为$(...)不解释引号或转义。 (除非用引号括起来,否则的结果$(...)会受到分词和路径名扩展的影响。)因此以下内容不会执行您想要的操作:

ls $(find ... -exec bash -c 'printf "%q " "$@"' printf {} +)

你需要做的是:

eval "ls $(find ... -exec bash -c 'printf "%q " "$@"' printf {} +)"

(请注意,我并没有真正尝试测试上述怪物。)

但那么你不妨这样做:

find ... -exec ls {} +

相关内容