我尝试执行此命令:
#!/bin/sh
cmd="ls *.txt | sed s/.txt//g"
for i in `$cmd`
do
echo $i
echo "Hello world"
done
也就是说,在当前工作目录中获取扩展名为.txt的内容,并从文件中删除.txt部分,然后打印出来。但是,我收到了此错误,似乎ls正在解释“|“和“sed”和“s/.txt//g”作为文本文件名:
ls: s/.txt//g: No such file or directory
ls: sed: No such file or directory
ls: |: No such file or directory
如果我将命令传递为for i in ls *.txt | sed s/.txt//g
,这不是问题。
3条答案
按热度按时间roqulrg31#
有几点:
$cmd
的行为与运行具有cmd
内容的命令的行为不同的直接原因。eval
为何容易造成安全性风险。sed
。请参见the bash-hackers' wiki page on parameter expansion,它描述了${var%suffix}
如何扩展为删除suffix
后的$var
的内容。ls *.txt
中,不是ls
计算*.txt
glob:* shell本身会在启动ls
可执行文件之前执行此操作 *。因此,根本没有必要运行ls
:shell的内置功能生成了文件名列表,因此您最好使用该列表。djmepvbi2#
试试这个
简单而有效。
z18hc3ub3#
基本问题是扩展的顺序(请参阅man bash中的EXPANSION):
展开的顺序为:大括号扩展、代字号扩展、参数、变量和算术扩展以及命令替换(以从左到右方式进行)、单词拆分和路径名扩展。
换句话说,命令替换已经假定原始行被拆分为单个命令,并且它将不识别“|“、”;“和其他bash关键字。
如果命令是常量,简单的解决方案是内联它:
从OP看,命令必须是变量。在这种情况下,可以使用“eval”强制将变量重新解析到管道中:
请务必阅读所有关于使用“eval”和动态构造命令的警告。
次要注解:在
sed
中,命令's/.txt//g'假定.txt
是正则表达式。因此,它会将btxt.txt
更改为.txt
。请确保对'.'进行转义,以便将其视为文字。