从 bash 脚本运行构造的命令

从 bash 脚本运行构造的命令

我在 bash 脚本中构建了这样的命令

a="my_cmd";
a="$a --verbose";
echo $a;
$a;

它可以正常工作并正确执行我的命令。但是当我向混合中添加环境变量时,它就会崩溃。

a="my_cmd";
a="URL=myurl $a --verbose";
echo $a;
$a;

它在“URL=myurl”处中断,显示“没有这样的文件或目录”,但如果我使用 eval() 运行它,则该命令可以正常工作。

a="my_cmd";
a="URL=myurl $a --verbose";
echo $a;
eval "$a";

为什么在混合中添加环境变量会破坏我在第二个示例中的命令。

答案1

当您将变量扩展保留为未加引号时,它会经历分词文件名扩展(即通配符)。它不会被解析为 shell 命令。一般来说,当您动态构造要执行的 shell 代码片段时,执行它的正确方法是eval "$a"包含a要解析为 shell 代码的字符串。

在您的第一个片段中, 的值a是 string my_cmd --verbose。分词将其分成两个单词my_cmd--verbose。通配符不会执行任何操作,因为任何单词中都没有通配符。因此,扩展后的命令由两个单词和$a组成,因此该命令(可以是别名、函数、内置命令或 PATH 中的可执行文件)使用单个参数 执行。my_cmd--verbosemy_cmd--verbose

在第二个片段中,情况类似,扩展后产生了三个单词:URL=myurl,my_cmd--verbose。这会导致尝试使用URL=myurl两个参数执行该命令。

shell 命令的URL=myurl my_cmd --verbose解析方式不同:第一个单词被解析为对变量 的赋值URL,并且由于其后有一个命令名称,因此赋值仅在命令持续时间内设置环境变量。这是解析的一部分,而不是扩展后完成的事情,因此它要求等号是 shell 源代码的一部分,等号不能是某些扩展的结果。

不要将带有参数的命令存储到字符串中。使用数组。对于复杂的命令,例如除了运行命令之外还设置变量或执行重定向的命令,如果可能,请使用函数,如果不使用,则使用函数eval(特别注意正确引用)。

相关内容