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 f
or -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)
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)