如何在不额外引用的情况下将 bash 变量作为命令运行?

如何在不额外引用的情况下将 bash 变量作为命令运行?

我正在尝试制作一个脚本,该脚本需要保存要作为字符串运行的命令。有问题的字符串需要包含引号,当尝试执行它时,bash 会添加额外的引号字符,这在某些情况下会导致命令无法按预期运行。

这是一个示例脚本。在此示例脚本中运行的命令example显然不会执行任何操作,它只会说command not found,但是您仍然可以运行该脚本并查看我在说什么,因为我添加到了-x#!/bin/bash行,以便打印出正在运行的确切命令。

例子:

#!/bin/bash -x

#command typed explicitly
example -options "-i filename"

#command stored in string first
commandstring='example -options "-i filename"'
echo "running command: ${commandstring}"
${commandstring}

为我运行此脚本的输出是(忽略两个“命令未找到”错误):

+ example -options '-i filename'
+ commandstring='example -options "-i filename"'
+ echo 'running command: example -options "-i filename"'
running command: example -options "-i filename"
+ example -options '"-i' 'filename"'

因此,您可以看到第一行当然按预期运行,给出了命令行参数:

-i filename

然而,尽管该echo命令以同样可以完美执行的方式打印字符串,但当将字符串放在命令行上时,它会发生变化,并且传入的参数会变成

''-i' '文件名''

其中包含额外的引号字符,这导致我在真实脚本中使用的实际命令失败。

有什么办法可以防止这种情况发生吗?

答案1

如果您使用的是bash,准确保存命令的最简单方法是将其放入数组中。如果您要运行的命令是:

example -options "-i filename"

您可以将其保存在数组变量中:

commandline=(example -options "-i filename")

然后,您可以通过 @ 扩展双引号内的数组来运行保存的命令:

"${commandline[@]}"

这里要知道的关键是,"'\当直接在命令行中输入时,shell 对引号字符 () 的处理方式与在变量扩展中(如${commandstring}.在命令行中,引号字符具有特殊的引用功能。在参数扩展中,它们只是普通的非特殊字符。因此,"-i filename"是在命令行中键入时被解析为 的单个单词-i filename,但变量中的相同字符扩展为单词"-ifilename"


Bash常见问题解答 50更详细地涵盖了这个主题。

相关内容