如果我有一个目录,其中包含一些名称带有空格的文件,例如
$ ls -1 dir1
file 1
file 2
file 3
我可以成功地将它们全部复制到另一个目录,如下所示:
$ find dir1 -mindepth 1 -exec cp -t dir2 {} +
但是, 的输出find dir1 -mindepth 1
包含未转义的空格:
$ find dir1 mindepth 1
dir1/file 1
dir1/file 3
dir1/file 3
如果我使用print0
而不是print
,输出仍然包含未转义的空格:
$ find dir1 mindepth 1 -print0
dir1/file 1dir1/file 2dir1/file 3
要使用 手动复制这些文件cp
,我需要转义空格;但当cp
's 参数来自时find
,无论我是否使用+
或\;
在命令末尾,这似乎都是不必要的。
这是什么原因呢?
答案1
命令find
直接执行命令。该命令(包括文件名参数)不会被 shell 或任何其他可能修改文件名的东西处理。这是非常安全的。
您是正确的,无需转义命令行{}
上表示的文件名find
。
find
将原始文件名从磁盘直接传递到命令的内部参数列表中-exec
,在您的例子中是cp
命令。
答案2
问题分为两部分:
- 如何做
find
设法调用程序,-exec
而不会遇到文件名中嵌入空格的问题,并且 - 这个选项有什么好处
-print0
?
第一个find
是进行系统调用,实际上是一组相关调用中的一个,称为“执行”。它将文件名作为参数直接传递给此调用,然后直接传递该调用(在创建新进程之后),而不会丢失有关文件名的信息。
SVR4 实用程序的一个特点
find
是-exec
初级的 + 终止符。这允许文件名包含特殊字符(特别是新队字符)被分组在一起,而不会出现如果这些文件名通过管道传输到xargs
.其他实现添加了其他方法来解决此问题,特别是使用-print0
空字节终止符写入文件名的主实现。这里考虑过这一点,但没有被采纳。使用空终止符意味着任何要处理 find-print0
输出的实用程序都必须添加一个新选项来解析它现在要读取的空终止符。
那 ”尤其a -print0
Primary”指的是 GNU find
,xargs
它以不同的方式解决问题。FreeBSD 也支持它find
和xargs
。如果您添加了一个-0
选项(请参阅手册页) 到xargs
调用,那么该程序接受以“空字节”字符结尾的行。依次xargs
调用执行- 要做的功能它是工作。-print0
和-0
功能与功能之间的主要区别+
在于,前者通过管道传递文件名,而后者则不然。开发人员几乎可以找到任何功能的用途;管道也不例外。
回到 OP 的示例,它使用了一个在 中找不到的-t
选项:cp
POSIX cp。相反,它是由以下提供的扩展(也称为“非标准功能”)GNU cp。-0
的扩展不会xargs
改进这个例子,但在其他情况下它可以被有效地使用——记住有+
GNUfind
接受的可移植替代方案。
答案3
(这应该是一个评论,但它太大了。)
对于那些喜欢尝试的人:
创建一个列出传入位置参数的脚本,将其命名为list_positional_parameters.sh
.
#!/bin/bash
# http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_09_07.html
# Try globbing patterns, e.g. "X[[:digit:]][[:digit:]]" to see what happens
if [ $# -lt 1 ]; then
echo "Usage: $0 and then at least one parameter"
exit 1
fi
counter=1
while (($#)); do
echo "$counter = '$1'"
# pop positional argument 1 off the stack of positional arguments
shift
(( counter++ ))
done
在某个目录 $dir 上运行find
它:
find "$dir" -exec ./list_positional_parameters.sh '{}' ';' | less
正如预期的那样,所有调用中只有一个参数,即文件名,无论其名称中是否有空格。