我目前在本地计算机上计算一些环境变量$FOO
。现在,我有了一个SSH脚本,其中包含一些命令,其中一些命令使用$FOO
仅在本地计算机上设置的环境变量。
我想在远程计算机上运行这些命令,但我想替换的本地版本,$FOO
以便当SSH脚本在远程计算机上运行时,它将使用本地计算得出的值$FOO
。我需要执行此操作,因为命令在远程计算机上的运行方式取决于$FOO
我计算出的本地值。
我知道您可以ssh user@remote < script.sh
在远程计算机上运行本地Shell脚本,但是我不确定如何执行该过程,但是需要使用上面提到的本地 $FOO
环境变量。我不想在本地或远程计算机上配置SSH,因此SendEnv
这不是我的选择。
用本地环境变量运行Shell脚本中具有的那些命令的最佳方法是什么$FOO
?
我假设您知道什么外壳程序应解释该脚本。此示例使用sh
:
# somewhat flawed
ssh user@remote "FOO='$FOO' exec sh" < script.sh
本地shell将被替换,$FOO
因为它被双引号(is)。单引号用于远程外壳程序(即exec
末尾的原始远程外壳程序sh
)。
注意ssh
将整个命令作为字符串传递。它将在远端进行解释。如果$FOO
扩展为包含一个或多个单引号的字符串,则整个命令可能行为不当。代码注入是可能的。
要“撤消”可能的单引号,可以尝试以下方法:
# still somewhat flawed
FOOx="$(printf '%s' "$FOO" | sed "s|'|'\"'\"'|g")"
ssh user@remote "FOO='$FOOx' exec sh" < script.sh
在我的Debian 9中,每个'
in都更改$FOO
为'"'"'
in $FOOx
。分析远程外壳程序中的引用以查看中心单引号在字面上会继续存在。
我可以在没有额外变量的情况下执行此操作:
# still somewhat flawed
ssh user@remote "FOO='$(printf '%s' "$FOO" | sed "s|'|'\"'\"'|g")' exec sh" < script.sh
它没有我希望的那么坚定。问题:
sed
输入是不完整的行(没有结尾的换行符),则可能会打印一条完整的行(带有结尾的换行符)。或者sed
可以忽略不完整的行。如果变量的内容不以换行符结尾,则这非常重要。$()
删除所有尾随的换行符。为了解决这些问题,我x
在之前附加了一个换行符sed
。然后,该工具(与实现无关)应接受所有内容,不应添加任何内容。然后$()
将仅删除多余的换行符。我删除了x
远端的多余部分。像这样:
# foolproof (AFAIK)
ssh user@remote "FOO='$(printf '%sx\n' "$FOO" | sed "s|'|'\"'\"'|g")'; FOO=\"\${FOO%x}\" exec sh" < script.sh
笔记:
$FOO
扩展为肯定不含单引号的字符串,则可以使用第一个最简单的命令。如果您的本地shell是Bash,则可以'"'"'
在扩展时将单引号替换为:
# foolproof (AFAIK), needs local Bash
pattern="'"
replacement="'\"'\"'"
ssh user@remote "FOO='${FOO//$pattern/$replacement}' exec sh" < script.sh
这解决了单引号的问题,并且不使用$()
也不使用sed
,因此不会出现其他提到的问题。我使用了其他变量来避免此问题。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句