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以执行。通过转义来解决问题,因为您无需逃避任何操作。它不会在远程主机上创建文件,并且您可以轻松运行非常复杂的脚本。评论
甚至:ssh user @ remotehost“ echo`base64 -w0 script.sh | base64 -d | sudo bash”
–尼古拉斯B.
2014年9月3日23:49
值得注意的是,在大多数情况下,可以将lzop或gzip替换为base64,以加快传输速度。但是,可能存在边缘情况。 YMMV。
– CodeGnome
2014年9月4日在12:29
请注意,但如果是脚本,我希望任何传输都不会超过几kb。
–ThoriumBR
2014年9月4日12:33
这里也有无用的回声用法。 base64脚本| ssh remotehost'base64 -d | sudo bash'就足够了:)
–霍布斯
2014年9月5日在7:48
虽然我还没有测试过该解决方案,但是它会输出脚本的结果,例如在stdout中输出'yum check-update'吗?我想问一下,因为如果有人认为我做的事情显然很幼稚,那么我只能捡些东西。
– Soham Chakraborty
16年8月22日在7:52
#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
技巧。 评论
当然:!cat%| (command)可以用:w!(command)或:!(command)<%来完成。
–斯科特
2014年9月4日于17:51
是。我的路线是虐待猫
– moebius_eye
2014年9月5日在9:13
运行ssh -tt导致我的ssh在某些命令运行后不会终止(在末尾添加退出无济于事)
–user498092
18/12/7在10:01
#3 楼
我认为最简单的解决方案是修改@thanasisk的注释。创建脚本,
scp
到计算机上,然后运行它。将脚本
rm
放在开始。外壳程序已打开文件,因此已将其加载,然后可以毫无问题地将其删除。在某个时候失败。#4 楼
您可以将%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'")"
评论
这是一个很棒的解决方案。实际上,在类似情况下,我以前必须使用过printf,但是我总是忘记了。感谢您发布此:-)
–乔恩·L。
15年4月23日在7:26
#5 楼
更新:示例现在显式使用sudo
。这是一种将Bash语法与复合赋值结合使用的方法,可通过sudo通过SSH执行任意复杂的命令: br />正确格式化命令以便在其他地方动态执行(例如嵌套shell,远程SSH shell等)可能非常棘手-有关原因的详细说明,请参见https://stackoverflow.com/a/53197638/111948。复杂的bash结构(如上面的语法)可以帮助这些命令正常工作。有关
cat
和<<
如何组合以形成内联此处文档的更多信息,请参见https://stackoverflow.com/a / 21761956/111948 评论
这个问题要求一个sudo命令。
– Pedro Vagner
20-4-2在21:19
@PedroVagner-感谢您指出,我已经相应更新了我的答案。
– Dejay Clayton
20-4-6的16:40
#6 楼
您是否知道可以使用sudo
给您一个Shell,您可以在其中以所选用户身份运行命令?-i,--login
运行目标用户的密码数据库条目指定的shell作为登录shell。这意味着外壳将读取特定于登录的资源文件,例如
.profile或.login。如果指定了命令,则通过外壳的-c选项将其传递到外壳以执行。如果未指定
命令,则执行交互式shell。 sudo尝试在运行外壳程序之前更改为该用户的主目录。该命令在与用户登录时所接收的环境类似的环境下运行。sudoers(5)手册中的“命令环境”部分介绍了-i选项如何影响该环境。使用sudoers策略时在其中运行命令的环境。
评论
这似乎是我的明显解决方案。 >须藤-i -u brian
– code_monk
2014年9月7日,下午2:26
在远程访问的情况下,与“ ssh -t”结合使用时效果最佳。该问题已包含在内,但需要重复“我看不懂此/ whole /页面”的内容。 :)
– dannysauer
15年7月13日在17:57
#7 楼
您可以在本地计算机上定义脚本,然后将其定义并通过管道传输到远程计算机: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
评论
您可以使用的UUOC <
–user9517
2014年9月2日,9:54
您可以修改示例以包括sudo -u scriptuser吗?考虑到我需要在要传递给计算机的脚本中使用变量,heredoc会有用吗?
–VoY
2014年9月2日上午10:36
我正在尝试:echo“ sudo`cat fileForSsh.txt`” | ssh ...但我一直在获取sudo:抱歉,您必须有一个tty才能运行sudo。
–jas_raj
2014-09-2 10:49
尽管如果可以更改/ etc / sudoers文件,此问题可能会有所帮助
– jas_raj
2014年9月2日在10:51
这对我有用:ssh -tq user @ host“ sudo bash -s”
– AVee
2014年9月4日18:00
#8 楼
简单容易。ssh user @ servidor“ bash -s”
#9 楼
如果使用足够现代的Bash shell,则可以将命令放入函数中,然后使用export -p -f function_name
将其打印为字符串。然后,该字符串的结果可以包含不一定必须以root用户身份运行的任意命令。/>
#!/bin/bash
remote_main() {
local dest="$HOME/destination"
tar xzv -C "$dest"
chgrp -R www-data "$dest"
# Ensure that newly written files have the 'www-data' group too
find "$dest" -type d -exec chmod g+s {} \;
}
tar cz files/ | ssh user@host "$(declare -pf remote_main); remote_main"
检索到的示例将保存登录用户的文件,并为根安装程序:
remote_main() {
wget https://example.com/screenrc -O ~/.screenrc
sudo apt-get update && sudo apt-get install screen
}
ssh user@host "$(declare -pf remote_main); remote_main"
如果要使用
sudo
运行整个命令,则可以使用以下命令:remote_main() {
wget https://example.com/screenrc -O ~user/.screenrc
apt-get update && apt-get install screen
}
ssh user@host "$(declare -pf remote_main);
sudo sh -c \"$(declare -pf remote_main); remote_cmd\""
# Alternatively, if you don't need stdin and do not want to log the command:
ssh user@host "$(declare -pf remote_main);
(declare -pf remote_main; echo remote_cmd) | sudo sh"
#10 楼
这是我(未经实际测试)的cr脚解决方案:#!/usr/bin/env ruby
# shell-escape: Escape each argument.
ARGV.each do|a|
print " '#{a.gsub("'","\'\\'\'")}' "
end
不行: />下一步是创建一个已经执行此操作的
betterssh
脚本:ssh -tq myuser@hostname "$(shell-escape sudo -u scriptuser bash -c "$(shell-escape ls -al)")"
#11 楼
对于需要将参数传递给脚本的这些人,应如下所示:ssh user@remotehost "echo `base64 -w0 script.sh` | base64 -d | sudo bash -s <param1> <param2> <paramN>"
#12 楼
首先,创建一个本地脚本,然后使用以下命令远程执行它:cat <Local Script.sh> | ssh user@server "cat - | sudo -u <user> /bin/bash"
评论
将脚本复制到$ remote,然后执行。那行得通,但是我发现一个不留下任何脚本文件的解决方案(以防万一失败等等)会更干净一些。
每次运行结束时都有脚本rm本身
考虑使用fabric fabfile.org。如果您需要远程进行sudo操作,可以使您的生活更加轻松。
如果您已安装Ansible,则此命令将显示您的用例的文档:ansible-doc脚本