我正在运行这个命令:
find ./ -type f -printf "wc -l \"%p\"\n"
这给出了这个输出:
wc -l "ANLS 457567.pl"
wc -l "ANLS 457567.pl"
现在我想将整行作为另一个命令运行。
我怎样才能实现这个目标?
我知道我可以用来xargs
将其输出作为参数传递给另一个命令,但出于好奇,我想知道是否(作为另一个命令运行命令输出行)是可能的。
答案1
虽然您可以将这样的命令通过管道传输到 shell,但它可能会出现一些非常问题,因为任何 glob 和变量以及其他内容都将被扩展。
包含例如星号(*
、 glob)或美元符号($
、变量和命令扩展)的文件名将导致问题。您需要确保正确引用所有内容,并且在一般情况下,您的文件名本身可以包含引号,因此这并不容易。
但在 的情况下find
,它可以自己执行外部命令:
find ./ -type f -exec wc -l {} \;
the{}
被当前文件名替换,并且末尾的(带引号的)分号是必需的。
至少某些版本find
支持另一种格式,可以一次性给出多个文件名来执行命令,从而节省大量执行:
find ./ -type f -exec wc -l {} \+
答案2
只需将其传递给 shell 的 STDIN:
find ./ -type f -printf "wc -l \"%p\"\n" | sh
或者如果 shell 支持进程替换,则<()
:
sh <(find ./ -type f -printf "wc -l \"%p\"\n")
只需find
:
find ./ -type f -exec wc -l {} +
答案3
有关此案例的实际解决方案,请参阅@ilkkachu 评论。但除此之外,shell 在执行每一行之前都会扩展变量,因此
find ./ -type f -printf "wc -l %p\n" | while read line; do
$line
done
会工作得很好(除非在文件名中找到特殊字符 - 例如空格)。
请注意$line
周围没有引号,我们也没有引用%p
。那是因为我们想shell 在执行之前将行分割成单词——将单词视为$line
命令及其参数,就像您自己编写它们一样。这就是空格不起作用的原因。
通过使用内置的 shell 可以避免这种情况eval
,真的就像您在 shell 中输入命令一样工作 - 包括引号(现在又回来了):
find ./ -type f -printf "wc -l \"%p\"\n" | while read line; do
eval $line
done
最后一个应该适用于所有情况 - 但仍然不是一个好的做法。eval
应该是最后的手段。我包含这些选项只是为了让您知道它们有效,但通常有更好的方法,-exec
例如find
.