题 如何在ssh上使用sudo运行任意复杂的命令?


我有一个系统,我只能在我的用户名(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 /某个目录,其中包含一个空格。

有没有一个通用的解决方案允许我传递任何命令,无论引用有多复杂/疯狂,或者这是否达到某种限制?还有其他可能的,可能更具可读性的解决方案


76
2017-09-02 09:21




将脚本复制到$ remote然后执行它。 - Iain
这可行,但我找到一个解决方案,不留下任何脚本文件(如果出现故障等)将更清洁。 - VoY
在每次运行结束时都有脚本rm - thanasisk
考虑使用面料 fabfile.org。如果你不得不远程sudo,可以让你的生活更轻松。 - Nils Toedtmann
如果安装了Ansible,则此命令显示用例的文档:ansible-doc脚本 - bbaassssiiee


答案:


我有时使用的一个技巧是使用base64对命令进行编码,并将其传输到另一个站点上的bash:

MYCOMMAND=$(base64 -w0 script.sh)
ssh user@remotehost "echo $MYCOMMAND | base64 -d | sudo bash"

这将编写脚本,在安全字符串中包含任何逗号,反斜杠,引号和变量,并将其发送到其他服务器。 (-w0 需要禁用换行,默认情况下会在第76列发生。另一方面, $(base64 -d) 将解码脚本并将其提供给bash以执行。

无论脚本多么复杂,我都没有遇到任何问题。通过转义解决问题,因为您不需要逃避任何事情。它不会在远程主机上创建文件,您可以轻松地运行极其复杂的脚本。


138
2017-09-02 13:10



甚至: ssh user@remotehost "echo `base64 -w0 script.sh` | base64 -d | sudo bash" - Niklas B.
值得注意的是,在大多数情况下,您可以用lzop或gzip替换base64以获得更快的传输时间。但是,可能存在边缘情况。因人而异。 - CodeGnome
好注意,但如果它是一个脚本,我不希望任何转移超过几kb。 - ThoriumBR
这里也有无用的回声。 base64 script | ssh remotehost 'base64 -d | sudo bash' 就够了:) - hobbs
今天测试并完美地工作。谢谢大家。 - Soham Chakraborty


-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 特技。


32
2017-09-02 13:01



当然 :!cat % | (command) 可以做到 :w !(command) 要么 :!(command) < %。 - Scott
是。我的路线是 虐待猫 - moebius_eye


我认为最简单的解决方案是修改@ thanasisk的评论。

创建一个脚本, scp 它到机器,然后运行它。

有脚本 rm 本身就在一开始。 shell已打开文件,因此已加载,然后可以毫无问题地删除。

按此顺序做事(rm 首先,其他的东西第二)它甚至会在某些时候失败时被删除。


9
2017-09-02 11:26





你可以使用 %q 格式说明符 printf 为你处理变量转义:

cmd="ls -al"
printf -v cmd_str '%q' "$cmd"
ssh user@host "bash -c $cmd_str"

printf -v 将输出写入变量(在这种情况下, $cmd_str)。我认为这是最简单的方法。没有必要传输任何文件或编码命令字符串(尽可能多的我喜欢的技巧)。

这是一个更复杂的例子,表明它适用于方括号和&符号之类的东西:

$ ssh user@host "ls -l test"
-rw-r--r-- 1 tom users 0 Sep  4 21:18 test
$ cmd="[[ -f test ]] && echo 'this really works'"
$ printf -v cmd_str '%q' "$cmd"
$ ssh user@host "bash -c $cmd_str"
this really works

我还没有测试过 sudo 但它应该如此简单:

ssh user@host "sudo -u scriptuser bash -c $cmd_str"

如果需要,可以跳过一步并避免创建中间变量:

$ ssh user@host "bash -c $(printf '%q' "$cmd")"
this really works

或者甚至完全避免完全创建变量:

ssh user@host "bash -c $(printf '%q' "[[ -f test ]] && echo 'this works as well'")"

7
2017-09-04 20:10



这是一个很棒的解决方案。我实际上不得不在之前使用printf来处理类似情况,但我总是忘记它。感谢您发布此内容:-) - Jon L.


这是在bash中执行类似这样的事情的“正确”(语法)方法:

ssh user@server "$( cat <<'EOT'
echo "Variables like '${HOSTNAME}' and commands like $( uname -a )"
echo "will be interpolated on the server, thanks to the single quotes"
echo "around 'EOT' above.
EOT
)"

ssh user@server "$( cat <<EOT
echo "If you want '${HOSTNAME}' and $( uname -a ) to be interpolated"
echo "on the client instead, omit the the single quotes around EOT."
EOT
)"

有关其工作原理的详细说明,请参阅 https://stackoverflow.com/a/21761956/111948


6
2018-05-28 17:48





你知道吗,你可以使用 sudo 给你一个shell,你可以在其中运行所选用户的命令?

-i, - login

将目标用户的密码数据库条目指定的shell作为登录shell运行。这意味着特定于登录的资源文件,例如                    .profile或.login将由shell读取。如果指定了一个命令,它将通过shell的-c选项传递给shell执行。如果不                    指定了命令,执行交互式shell。在运行shell之前,sudo尝试更改为该用户的主目录。 com-                    mand的运行环境类似于用户在登录时收到的环境。在sudoers(5)手册中的命令环境部分 -                    -i选项如何影响正在使用sudoers策略时运行命令的环境。


4
2017-09-03 09:22



这对我来说似乎是一个明显的解决方案。 > sudo -i -u brian - code_monk
在远程访问的情况下与“ssh -t”结合使用时效果最佳。这个问题包括在内,但是对于“我无法阅读这个/整个/页面”的人来说,这些都是重复的。 :) - dannysauer


您可以在本地计算机上定义脚本,然后 cat 并将其管道到远程机器:

user@host:~/temp> echo "echo 'Test'" > fileForSsh.txt
user@host:~/temp> cat fileForSsh.txt | ssh localhost

Pseudo-terminal will not be allocated because stdin is not a terminal.
stty: standard input: Invalid argument
Test

3
2017-09-02 09:39



UUOC你可以用< - Iain
您可以修改要包含的示例吗? sudo -u scriptuser?考虑到我需要在脚本中使用变量来管理机器,heredoc是否可用? - VoY
我在努力: echo "sudo `cat fileForSsh.txt`" | ssh ... 但我一直在 sudo: sorry, you must have a tty to run sudo。 - jas_raj
虽然 这个问题 如果你能得到,可能会有所帮助 /etc/sudoers 文件已更改 - jas_raj
这对我有用: ssh -tq user@host "sudo bash -s" < test.sh - AVee


简单易行。

ssh user @ servidor“bash -s”<script.sh


1
2017-09-03 20:15