我有一个命令存储在变量中。假设该变量$i
具有以下值:
cat -nT index.php |grep 'someregex'
当我尝试通过键入来执行上述变量时,$i
它会失败,因为 shell 会尝试将整个变量作为一个命令来执行。我还尝试使用eval($i)
并$i
输入反引号。
我怎样才能让 shell$i
像命令一样执行?为什么它的工作方式不一样。
$i='echo hi'; $i
是不是因为我必须对单引号进行某种破解?(因为你不能嵌套它们。)目前我的解决方案是
echo $i > /foo; . /foo
但我不想为此而创建一个文件,然后稍后再删除它。
我说的“我破解了单引号”的意思是:
$i='cat index.php | grep -P '"'"'MYREGEXHERE'"'"
答案1
简短回答:参见BashAQ #50:我试图将命令放入变量中,但复杂的情况总是失败!。
长答案:这是因为 bash 解析命令行的顺序。具体来说,它在扩展变量值之前会查找管道和重定向之类的东西,并且不会返回并在扩展的值中重新查找管道等。本质上,变量在解析过程的一半左右被替换,因此该值在执行之前只被解析了一半。
为了解决这个问题,您需要回答@slhck的问题:为什么命令首先存储在变量中?您试图解决的实际问题是什么?根据实际目标,有许多可能的解决方案:
不要将其存储在变量中,直接执行即可。存储命令以供日后使用比较棘手,如果不需要,就不要存储。
使用函数而不是变量。毕竟,这就是它们的用途:
i() { cat -nT index.php |grep 'someregex'; } i
这样做的主要缺点是您不能动态地创建函数——您不能有条件地在函数中包含或排除代码(尽管函数本身可以具有执行时选择的条件元素)。
使用
eval
。这应该被视为最后的手段,因为很容易出现意外行为。它本质上是通过另一次完整的解析过程运行命令,因此所有管道等都会获得其完整含义——但这也意味着您认为只是数据的命令部分也将被解析并可能执行。包含 shell 元字符(管道、分号、引号/撇号等)的文件名可能会产生奇怪且有时危险的影响。如果您确实使用eval
,至少要用双引号括住字符串,否则其内容实际上会被解析一次半,结果甚至更奇怪。i="cat -nT index.php |grep 'someregex'" eval "$i"
编辑:另一种标准的将命令存储在变量中的方法是使用数组而不是简单变量。这允许您毫无困难地存储带有复杂参数(例如包含空格)的命令,但不会存储诸如管道和重定向之类的内容。因此,数组方法在这种特定情况下不会有用。
答案2
这应该可以工作:
a="cat -nT index.php |grep 'someregex'"
eval "$a"
请注意,这eval
会引入潜在的漏洞和意外行为情况,因此必须格外小心地使用。
答案3
声明变量时,不应使用美元符号作为前缀。
尝试这个:
i='echo hi'; $i