在命令之前设置 shell 变量给出“命令未找到”

在命令之前设置 shell 变量给出“命令未找到”

我正在尝试设置一个 shell 变量并将其作为 Shell 脚本的一部分传递到命令中,代码如下:

SLS_DEBUG_TEXT=""
if [ "$ENABLE_DEBUG_LOGGING" = "true" ]; then
  SLS_DEBUG_TEXT="SLS_DEBUG=* "
fi

$SLS_DEBUG_TEXT sls create_domain -v $AWS_PROFILE_FLAG --stage $STAGE // gives error
#SLS_DEBUG=* sls create_domain -v $AWS_PROFILE_FLAG --stage $STAGE // works correctly

我收到的错误是:

./sls-deploy.sh: line 110: SLS_DEBUG_TEXT: command not found

if语句大多无关紧要,但我想表明该变量需要有条件地设置(即我并不总是希望启用调试日志记录)。代码片段中的最后一行(已被注释掉)是在启用调试日志记录并且正常工作的情况下该命令应该是什么样子的。

我在这里和 Stack Overflow 上发现了一些以前的帖子,其中问题是由于设置变量时等号之间的空格造成的(例子)但我不思考我在这里陷入了这个陷阱。

感谢您的帮助。

答案1

$SLS_DEBUG_TEXT在 shell 会将其值视为赋值的阶段之后,扩展得太晚了。因此,变量的值被视为命令。

你可以做的是使用env

SLS_DEBUG_TEXT='SLS_DEBUG=*'
env "$SLS_DEBUG_TEXT" sls create_domain -v "$AWS_PROFILE_FLAG" --stage "$STAGE"

注意周围的引用每个单个变量扩展

如果SLS_DEBUG_TEXT可能为空或未设置,则上述内容将生成错误,因为env将尝试执行没有名称的命令。

要解决这个问题,您可以使用

SLS_DEBUG_TEXT='SLS_DEBUG=*'
env ${SLS_DEBUG_TEXT:+"$SLS_DEBUG_TEXT"} sls create_domain -v "$AWS_PROFILE_FLAG" --stage "$STAGE"

如果该变量已设置且非空,则 会${SLS_DEBUG_TEXT:+"$SLS_DEBUG_TEXT"}扩展为。"$SLS_DEBUG_TEXT"否则它会扩展为空(甚至不是空字符串,这就是 的情况"$SLS_DEBUG_TEXT")。

还要注意,如果您有SLS_DEBUG_TEXT='SLS_DEBUG=* '(如在您的代码中),则 后面的空格将成为进程环境中*的值的一部分。我不知道这是有意还是无意。SLS_DEBUGsls


我还注意到您引用的错误消息说

./sls-deploy.sh: line 110: SLS_DEBUG_TEXT: command not found

对我来说,这表明您$在脚本中的某个时刻使用了变量的名称,而没有在它前面使用变量的名称。这可能与您遇到的主要问题完全无关。你的代码展示反而会导致错误

./sls-deploy.sh: line NNN: SLS_DEBUG=*: command not found

答案2

shell 语法在词法分析阶段识别赋值词,早在参数扩展发生之前。尽管您可以将参数扩展为命令,你不能将其扩展为一个作业——此时它只是被视为一条命令,即使它在文本上是相同的(就像你写的那样"SLS_DEBUG=*" sls ...)。

这是 shell 命令语言解析和评估的一个奇怪之处。某些类型的行为是在第一次读入代码时从词法上确定的,并且这些行为以后永远无法恢复,即使事情通常出现通过文本替换来工作。

使用SLS_DEBUG_TEXT="eval SLS_DEBUG='*' "它就会起作用,尽管如果命令的其余部分可以包含任何 shell 元字符,则可能会出现潜在问题。另一种选择是有条件地定义一个函数:

sls_debug() { :; }
if [ "$ENABLE_DEBUG_LOGGING" = "true" ]; then
    sls_debug() {
        SLS_DEBUG='*' "$@"
    }
fi
sls_debug sls create_domain ...

或者(也许更清楚)一个仅$ENABLE_DEBUG_LOGGING在内部检查的函数也可以工作,或者env "$SLS_DEBUG_TEXT" ...或者eval "$SLS_DEBUG_TEXT" ...也将是显式的。

答案3

为了完整起见,这就是我最终解决问题的方法,该问题结合了拘萨罗南达的回答迈克尔·霍默的回答

function executeServerlessCommand() {
  if [ "$ENABLE_SLS_DEBUG_LOGGING" = "true" ]; then
    SLS_DEBUG='*' "$@"
  else
    "$@"
  fi
}

executeServerlessCommand sls create_domain -v ${AWS_PROFILE_FLAG:+"$AWS_PROFILE_FLAG"} --stage "$STAGE"

一些注意事项:

  1. 我创建了一个函数,它接受要运行的命令,检查ENABLE_SLS_DEBUG_LOGGING变量并SLS_DEBUG=*在命令前面添加(如果为 true),否则执行提供的命令
  2. 我使用的${a:+"$a"}变量语法AWS_PROFILE_FLAG仅添加变量值(如果已设置)。以前这个变量没有被正确引用。

相关内容