如果命令 find -exec

Esr*_*ref 12 shell bash find command-substitution

我只是想列出当前目录下的所有目录和文件,并使用以下命令写入文件或目录:

find -exec echo `echo {} : ;if [ -f {} ]; then echo file; else echo directory;fi` \;
Run Code Online (Sandbox Code Playgroud)

我知道这是一个愚蠢的命令,我可以使用其他东西,例如-type for -type d,但我想了解为什么那段代码没有按我预期的那样工作。它只是将目录打印到所有这些。例如 while 的输出find是:

.
./dir
./dir/file
Run Code Online (Sandbox Code Playgroud)

我的代码的输出是:

. : directory
./dir : directory
./dir/file : directory
Run Code Online (Sandbox Code Playgroud)

和输出

echo `echo dir/file : ;if [ -f dir/file ]; then echo file; else echo directory;fi`
Run Code Online (Sandbox Code Playgroud)

dir/file : file
Run Code Online (Sandbox Code Playgroud)

我正在研究Ubuntu 14.10和使用find (GNU findutils) 4.4.2

Gil*_*il' 13

首先,您的代码段执行命令

echo {} : ;if [ -f {} ]; then echo file; else echo directory;fi
Run Code Online (Sandbox Code Playgroud)

因为它需要它的输出来评估命令替换。由于没有名为 的文件{},这会产生输出

{} :
directory
Run Code Online (Sandbox Code Playgroud)

然后find使用参数-exec, echo, {}, :,执行命令directory,因此对于每个文件,它输出文件名后跟一个空格和: directory

您真正想要做的是echo {} :; …find. 此代码段必须由由 产生的外壳执行find,而不是由启动的外壳执行find,因为它正在find从其命令行接收数据。因此,您需要指示find运行 shell:

find -exec sh -c 'echo {} : ;if [ -f {} ]; then echo file; else echo directory;fi' \;
Run Code Online (Sandbox Code Playgroud)

这更好,但仍然不对。find如果您的文件名不包含任何特殊字符,它将适用于某些(不是全部)实现,但是由于您在 shell 脚本中插入文件名,您允许文件名执行任意 shell 命令,例如,如果您有一个名为的文件,$(rm -rf /)然后rm -rf /将执行该命令。要将文件名传递给脚本,请将它们作为单独的参数传递。

此外,第echo一个在冒号后打印一个换行符。使用echo -n(如果您的外壳支持)或printf避免这种情况。

find -exec sh -c 'printf "%s :" "$0"; if [ -f "$0" ]; then echo file; else echo directory; fi' {} \;
Run Code Online (Sandbox Code Playgroud)

您可以使用-exec … {} +对 shell 调用进行分组,这样速度更快。

find -exec sh -c 'for x; do printf "%s :" "$x"; if [ -f "$x" ]; then echo file; else echo directory; fi; done' _ {} +
Run Code Online (Sandbox Code Playgroud)


nco*_*ers 6

if; then; else; fi与 with 一起执行的另一种方式find是:

find |
while read p; do if [ -f "$p" ]; then echo file; else echo directory; fi; done
Run Code Online (Sandbox Code Playgroud)