带变量替换的 Eval 和 exec

带变量替换的 Eval 和 exec

我想执行一条语句来启动服务器。为此,我有一个环境变量来确定要启动哪个服务器。我得到了这个命令作为起点:

eval "exec gunicorn --chdir /this/dir package.sub:call_main() -b 0.0.0.0:80"

由于我有几种服务器需要启动,我想参数化脚本。经过一番搜索,我发现报价是多余的。所以我现在拥有的是:

APP=main
eval exec gunicorn --chdir /this/dir package.sub:call_${APP}() -b 0.0.0.0:80

然而,这会产生一个syntax error near unexpected token '('.理想情况下,我什至希望有一个像 这样的默认参数${APP:-main},但我想一旦语法错误问题得到解决,这是可能的。

上面的说法有什么问题吗?另外,这里eval是否需要?exec

答案1

在第二段代码中,您删除了 参数周围的双引号eval。不要那样做。删除它们将使()shell 变得特殊(它启动一个子 shell)。

反而:

app=main
eval "exec gunicorn --chdir /this/dir package.sub:call_$app'()' -b 0.0.0.0:80"

eval在重新评估字符串时,仍然需要在此处引用括号。变量扩展将在调用$app之前完成。eval

或者,

app=main
eval "exec gunicorn --chdir /this/dir 'package.sub:call_$app()' -b 0.0.0.0:80"

这可能看起来更好。

请注意,除了紧跟在变量名中有效的字符(如)之外,${APP}和在各方面都是相同的。在这里,不需要。另外,使用小写变量名称以避免与现有环境变量发生意外冲突。$APP"${APP}x"{...}

我认为这里不需要evalexec。该字符串似乎不需要用andeval重新评估exec代替当前的 shell 进程gunicorn(我不知道这是否是你想要的)。

可能就足够了

app=main
gunicorn --chdir /this/dir "package.sub:call_$app()" -b 0.0.0.0:80

请注意双引号。

有关的:

答案2

您将执行一项复杂的任务:shell 应该执行 11 次传递(并且每次传递都会破坏输入,以便进行下一步)。

你的代码是

APP=main
eval exec gunicorn --chdir /this/dir package.sub:call_${APP}() -b 0.0.0.0:80

为了理解,删除 eval:

exec gunicorn --chdir /this/dir package.sub:call_${APP}() -b 0.0.0.0:80

注意:第一个示例类似,您删除了eval和 双引号,因此您仍然得到相同的输出。

现在你有了()保留的(这是特别的,因为在这种情况下不能以其他方式误解令牌:没有前缀,我们不在命令上下文中(因此调用子shell,使用括号)。注意:这是因为这 11 个步骤,以及标记化的顺序,我们大概就明白为什么会这样了(而且 shell 解析器是很久以前设计的,所以很简单)。

因此,您必须告诉 shell 将 () 传递到下一个解析器步骤。

您可以使用转义(\):

exec gunicorn --chdir /this/dir package.sub:call_${APP}\(\) -b 0.0.0.0:80

或引用:

exec gunicorn --chdir /this/dir package.sub:call_${APP}'()' -b 0.0.0.0:80

注意:您不需要引用整个“单词”(参数),您可以只引用一部分,这样就不需要单引号${APP}(需要扩展)。

对于第一个示例,您可以引用双引号:

eval "exec gunicorn --chdir /this/dir \"package.sub:call_main()\" -b 0.0.0.0:80"

这样 eval 将删除外部引号,并且 exec 将看到内部引号(未转义)

相关内容