![仅当通过 SSH 调用时,Bash 脚本才会出现“未绑定变量”错误](https://linux22.com/image/221746/%E4%BB%85%E5%BD%93%E9%80%9A%E8%BF%87%20SSH%20%E8%B0%83%E7%94%A8%E6%97%B6%EF%BC%8CBash%20%E8%84%9A%E6%9C%AC%E6%89%8D%E4%BC%9A%E5%87%BA%E7%8E%B0%E2%80%9C%E6%9C%AA%E7%BB%91%E5%AE%9A%E5%8F%98%E9%87%8F%E2%80%9D%E9%94%99%E8%AF%AF%20.png)
当我跑步时:
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
运行:
本地 shell 执行分词、删除引号(通常还有其他一些操作)。结果
ssh
可能会得到一个或多个参数,它会将其解释为要传递到远程端的代码。ssh
将这些参数与中间的空格连接起来,以便将单个字符串传递到远程 shell。远程 shell 自行执行分词、删除引号(以及通常的其他一些操作)。它运行一些命令。
如果命令是
bash -c …
另一个(远程)shell 将解析作为选项参数的代码-c
。分词、删除引号和其他操作也将由该 shell 执行。如果
deployJob.sh
包含一个理智的 shebang (或没有)然后会有另一个(远程)shell 依次解释该文件。
一般来说,在所有先前的工具消化了它们的参数之后,您需要预测并策划哪些工具会获得哪些参数;以及它将传递给下一个工具的参数是什么。您需要设计本地命令,以便最终的工具能够准确地获得您想要的结果。