我有一个只能以我的用户名 (myuser) 登录的系统,但我需要以其他用户 (scriptuser) 的身份运行命令。到目前为止,我已经想出了以下内容来运行我需要的命令:
ssh -tq myuser@hostname "sudo -u scriptuser bash -c \"ls -al\""
但是,当我尝试运行更复杂的命令时,例如,[[ -d "/tmp/Some directory" ]] && rm -rf "/tmp/Some directory"
我很快就会遇到引用问题。我不确定如何将这个示例复杂命令传递给bash -c
,当\"
已经界定了我传递的命令的边界时(所以我不知道如何引用/tmp/Some目录,其中包含空格)。
是否有一个通用的解决方案允许我传递任何命令,无论引用有多复杂/疯狂,或者这是我达到的某种限制?还有其他可能的、可能更易读的解决方案吗?
答案1
我有时使用的技巧是使用 base64 对命令进行编码,然后将其通过管道传输到另一个站点上的 bash:
MYCOMMAND=$(base64 -w0 script.sh)
ssh user@remotehost "echo $MYCOMMAND | base64 -d | sudo bash"
这将对脚本进行编码,将逗号、反斜杠、引号和变量放在安全字符串内,并将其发送到另一台服务器。(-w0
需要禁用换行,默认情况下换行发生在第 76 列)。另一方面,$(base64 -d)
将解码脚本并将其提供给 bash 执行。
无论脚本有多复杂,我从来没有遇到过任何问题。解决了转义问题,因为您不需要转义任何内容。它不会在远程主机上创建文件,您可以轻松运行非常复杂的脚本。
答案2
看到-tt
选项了吗?阅读ssh(1)
手册。
ssh -tt root@host << EOF
sudo some # sudo shouldn't ask for a password, otherwise, this fails.
lines
of
code
but be careful with \$variables
and \$(other) \`stuff\`
exit # <- Important.
EOF
我经常做的一件事就是使用 vim 并使用:!cat % | ssh -tt somemachine
技巧。
答案3
我认为最简单的解决方案在于修改@thanasisk 的评论。
创建一个脚本,scp
将其发送到机器,然后运行它。
将脚本rm
本身放在开头。shell 已打开该文件,因此已加载该文件,然后可以毫无问题地将其删除。
通过按此顺序执行操作(rm
首先,其次是其他内容),它甚至会在某个时候失败时被删除。
答案4
更新:示例现在明确使用sudo
。
以下是使用 Bash 语法和复合赋值通过 SSH 使用 sudo 执行任意复杂命令的方法:
CMD=$( cat <<'EOT'
echo "Variables like '${HOSTNAME}' and commands like $( whoami )"
echo "will be interpolated on the server, thanks to the single quotes"
echo "around 'EOT' above."
EOT
) \
SSHCMD=$(
printf 'ssh -tq myuser@hostname sudo -u scriptuser bash -c %q' "${CMD}" ) \
bash -c '${SSHCMD}'
CMD=$( cat <<EOT
echo "If you want '${HOSTNAME}' and $( whoami ) to be interpolated"
echo "on the client instead, omit the the single quotes around EOT."
EOT
) \
SSHCMD=$(
printf 'ssh -tq myuser@hostname sudo -u scriptuser bash -c %q' "${CMD}" ) \
bash -c '${SSHCMD}'
正确格式化命令以便在其他地方动态执行(例如嵌套 shell、远程 SSH shell 等)可能非常棘手 - 请参阅https://stackoverflow.com/a/53197638/111948以更好地解释原因。复杂的 bash 结构(如上述语法)可以帮助这些命令正常工作。
有关如何cat
以及<<
结合以形成内联的更多信息这里的文件, 请参见https://stackoverflow.com/a/21761956/111948