仅当通过 SSH 调用时,Bash 脚本才会出现“未绑定变量”错误

仅当通过 SSH 调用时,Bash 脚本才会出现“未绑定变量”错误

当我跑步时:

ssh [email protected] bash -c "/home/devops_staging/deployJob.sh example"

我遇到以下错误:

/home/devops_staging/deployJob.sh: line 4: $1: unbound variable

如果我在没有该bash -c部件的情况下运行它,它会按预期工作。

ssh [email protected] /home/devops_staging/deployJob.sh example
deploy success

为什么会出现这种情况?

这是非常出乎意料的,因为我似乎记得总是使用这种语法,ssh ... bash -c "commands param1 param2"没有任何问题。

有问题的脚本非常简单,我在第 4 行所做的就是分配一个变量$1(这应该是第一个参数):

#!/usr/bin/env bash
set -euo pipefail

CI_PROJECT_NAME="$1"
...

调试时bash -x -c ...我看到以下可疑的行:

 + '[' -z '' ']'
 + return
 + case $- in
 + return
 + /home/devops_staging/deployJob.sh
/home/devops_staging/deployJob.sh: line 4: $1: unbound variable

答案1

我认为这是以下问题的重复:带引号的 ssh 命令。已经注意到了,但作者在这里指出:

读完后我仍然不确定为什么它会这样工作

因此,这个答案试图在当前问题中使用的代码的上下文中具体解释该问题。

最重要的信息来自于此链接问题的好答案是:

SSH 在 shell 中执行远程命令。它将字符串而不是参数列表传递给远程 shell。传递给命令的参数ssh之间用空格连接。

如果你在本地运行

ssh [email protected] /home/devops_staging/deployJob.sh example

那么参数ssh被识别为要传递到远程端的代码将是:/home/devops_staging/deployJob.sh, example。参数串联的字符串将是

/home/devops_staging/deployJob.sh example

这将是在远程端运行的 shell 代码。碰巧这就是你想要的字符串。

但如果你在本地运行

ssh [email protected] bash -c "/home/devops_staging/deployJob.sh example"

那么参数将是:bash, -c/home/devops_staging/deployJob.sh example远程 shell 的字符串将是

bash -c /home/devops_staging/deployJob.sh example

(就好像参数是:bash, -c, /home/devops_staging/deployJob.sh, example)这是不是您想要在远程端运行的 shell 代码。这里example不属于选项参数-c(它就像第二sh这是另一个问题)。

如果您想要这个字符串作为远程代码:

bash -c "/home/devops_staging/deployJob.sh example"

那么最简单的方法是将字符串ssh作为单个参数传递给本地:

ssh [email protected] 'bash -c "/home/devops_staging/deployJob.sh example"'

单引号参数包含要传递给远程 SSH 服务器启动的 shell 的所有 shell 代码。

请注意,您甚至可以在本地执行此操作:

ssh [email protected] 'bash -c "/home/devops_staging/deployJob.sh' 'example"'

其中双引号(对于远程 shell)属于两个单独的本地参数,远程 shell 的结果字符串将是相同的。


请注意有多少工具解释和消化该命令,直到您(远程)中的代码deployJob.sh运行:

  1. 本地 shell 执行分词、删除引号(通常还有其他一些操作)。结果ssh可能会得到一个或多个参数,它会将其解释为要传递到远程端的代码。

  2. ssh将这些参数与中间的空格连接起来,以便将单个字符串传递到远程 shell。

  3. 远程 shell 自行执行分词、删除引号(以及通常的其他一些操作)。它运行一些命令。

  4. 如果命令是bash -c …另一个(远程)shell 将解析作为选项参数的代码-c。分词、删除引号和其他操作也将由该 shell 执行。

  5. 如果deployJob.sh包含一个理智的 shebang (或没有)然后会有另一个(远程)shell 依次解释该文件。

一般来说,在所有先前的工具消化了它们的参数之后,您需要预测并策划哪些工具会获得哪些参数;以及它将传递给下一个工具的参数是什么。您需要设计本地命令,以便最终的工具能够准确地获得您想要的结果。

相关内容