How to execute a remote command over ssh with arguments?
在我的.bashrc中,我定义了一个函数,稍后我可以在命令行中使用它:
1 2 3
| function mycommand() {
ssh user@123.456.789.0 cd testdir;./test.sh"$1"
} |
使用此命令时,仅在远程主机上执行cd命令;在本地主机上执行test.sh命令。这是因为分号分隔了两个不同的命令:ssh命令和test.sh命令。
我试图定义如下函数(注意单引号):
1 2 3
| function mycommand() {
ssh user@123.456.789.0 'cd testdir;./test.sh"$1"'
} |
我试图把cd命令和test.sh命令放在一起,但是$1的论点没有得到解决,与我给函数的内容无关。它总是试图执行一个命令
在远程主机上。
如何正确定义mycommand,使脚本test.sh在切换到目录testdir后,在远程主机上执行,能够把给mycommand的参数传递给test.sh?
- 这与主点无关,但您可能希望使用&&而不是分号来联接在远程主机上执行的命令:cd testdir && ./test.sh"$1"。使用这种形式(因为评估bash中的&&短路),如果cd失败,则不会执行第二个命令,并且不会无意中在user的homedir中运行不同的test.sh。
改为这样做:
1 2 3
| function mycommand {
ssh user@123.456.789.0"cd testdir;./test.sh "$1""
} |
您仍然需要将整个命令作为单个字符串传递,但是在该单个字符串中,您需要在发送到ssh之前扩展$1,因此需要使用""。
更新
另一个正确的方法实际上是使用printf %q正确地引用论点。即使参数有空格、单引号、双引号或对shell有特殊意义的任何其他字符,也可以安全地进行解析:
1 2 3 4
| function mycommand {
printf -v __ %q"$1"
ssh user@123.456.789.0"cd testdir;./test.sh $__"
} |
- 当用function声明函数时,不需要()。
- 不要仅仅因为你是一个姿态主义者就对它发表评论。
- 这很容易被命令注入…
- @Joso是的,这是它的基础,因此根据使用情况,用户可以选择清理他需要的参数。对于基本的ssh,可能没有更好的方法——除非先进行文件传输,等等。
- @joso是的,更好的方法是定义一个像quote() { printf"'%q'""$1"; }这样的引号函数,然后执行ssh user@host"cd testdir; ./test.sh $(quote"$1")"
- @奥古拉,几乎,但%q的结果是自引用的;用文字引用包围它们是不必要或不正确的。printf -v arg_str '%q '"$1"; ssh user@host"cd testdir; ./test.sh $arg_str"就足够了。
- @Charlesduffy为什么你需要增加空间?
- @KonsoleBox,就目前的情况而言,并不是真的,但是如果添加了更多的参数而不是将它们全部弄脏,那么这个习语就会扩展。
- @查理斯达菲接球不错,那是个打字错误。应该是printf"%q""$1"。
恢复一个旧的线程,但这个相当干净的方法没有列出。
1 2 3 4 5
| function mycommand() {
ssh user@123.456.789.0 <<+
cd testdir;./test.sh"$1"
+
} |
- 如果$1扩展到具有"和可扩展字符(如$和`)的字符串,这将失败。
- 它不会"失败"。它与使用参数执行任何非ssh命令的效果相同。这次行动并没有要求吸取双重逃避论点的教训。如何让他的第二个命令执行他已经准备好的论点。
- 如果用户询问如何在ssh上执行某个操作,那么可以期望任何答案涵盖ssh特有的警告(即在本地运行代码时不存在)。双重扩展(以及由此引起的shell注入漏洞)是此类警告之一,这些警告不存在于直接在本地shell中运行的cd testdir; ./test.sh"$1"中,但确实存在于给定的代码中。
- 我不认为你会反对一个数据库问题的答案,这个问题展示了一个有SQL注入漏洞的实践,但是有人通过mycommand '$(rm -rf ~)'运行任意远程代码的可能性是非常严重的。
- (…问题是,使代码安全所需的更改相当小:printf -v argv_str '%q '"$@"; ssh user@host"bash -s $argv_str" <<'+'和其余的可以保持不变;引用+符号作为heredoc阻止其扩展)。
- @"但是有人通过mycommand"$(rm-rf~)运行任意远程代码的可能性是非常严重的。"->我不明白这一点。有区别:错误的或意外的扩展与显式命令。你不能说他们给予平等的危险只是因为他们都给予危险。有度数或等级。
- @KonsoleBox,如果我运行for file in /data/**; do ./mycommand"$file"; done,我是否只是"显式"运行一个命令,因为data目录中的文件有恶意名称?将代码和数据分开(即,防止后者被错误地解析为前者)的一个要点是,代码应该完全由经过审计的人工控制,但数据通常来自不可信的来源。
- @KonsoleBox,…是的,易利用性确实存在差异,但这并不能成为已知可利用性的借口,因为它可以完全安全(不存在一些尚未完全未知的漏洞)。
这是一个在AWS云上工作的示例。场景是,一些从自动缩放启动的机器需要在另一台服务器上执行一些操作,通过ssh传递新生成的实例dns
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| # Get the public DNS of the current machine (AWS specific)
MY_DNS=`curl -s http://169.254.169.254/latest/meta-data/public-hostname`
ssh \
-o StrictHostKeyChecking=no \
-i ~/.ssh/id_rsa \
user@remotehost.example.com \
<< EOF
cd ~/
echo"Hey I was just SSHed by ${MY_DNS}"
run_other_commands
# Newline is important before final EOF!
EOF |
我正在使用以下命令从本地计算机远程执行命令:
1
| ssh -i ~/.ssh/$GIT_PRIVKEY user@$IP"bash -s" < localpath/script.sh $arg1 $arg2 |