# !/bin/bash
# tell bash to put a quoted string which will, if expanded by bash, evaluate
# to the original arguments to this script into cmd_str
printf -v cmd_str '%q ' "$@"
# on the remote system, run "bash -s", with the script to run fed on stdin
# this guarantees that the remote shell is bash, which printf %q quoted content
# to be parsed by.
ssh "$slave" "bash -s" <<EOF
$cmd_str
EOF
2条答案
按热度按时间sxissh061#
脚本中包含空格的参数需要在命令行中用引号括起来。
这个
${@// /\\ }
将引用此空白,以便接下来进行的扩展将保留空白作为另一个命令的参数的一部分。不管怎样,也许一个例子是正确的。用上述行创建tst.sh并使其可执行。
尝试在包含空格的目录的远程服务器(也称为slave)上运行mkdir命令,前提是您可以访问该目录
server
具有用户iduid
:由于引用了空格,您现在将有一个
dir with spaces
上的/tmp目录server
所有者uid
.检查使用
ssh uid@server ls /tmp
如果你在另一个国家,并且真的想要一些非英语字符,那就用$“…”来维持,也就是特定地区的。xwmevbvl2#
这段代码只是一个bug:它打算转义本地脚本的参数列表,以便可以通过ssh传输带有空格的参数,但它做得很糟糕(以可利用的方式丢失了某些类型的空格和大量的元字符类),并使用
$""
语法(执行翻译表查找)没有任何可理解的理由这样做。错误的事情(又名:它应该做什么,以及它如何失败)
第1部分:描述问题
将一系列参数传递给ssh并不能保证这些参数会按原来的方式出现!ssh将其参数列表展平为单个字符串,并仅将该字符串传输到远程系统。
因此:
…在远程系统看来完全一样:
…从而消除了引号的影响。如果你想要第一个命令的效果,你实际上需要的是这样的:
…其中命令及其引号作为单个参数传递给ssh。
第2部分:尝试修复
语法
"${var//string/replacement}"
计算的内容$var
但每一次string
替换为replacement
.语法
"$@"
扩展到给定给当前脚本的参数的完整列表。"${@//string/replacement}"
扩展到参数的完整列表,但每个string
在每个参数中替换为replacement
.因此,
"${@// /\\ }"
扩展到参数的完整列表,但每个空格都替换为一个字符串,该字符串在该空格前面加一个反斜杠。因此,它修改了这一点:
对此:
…宋承宪大口地说:
看起来不错,对吧?但事实并非如此。
旁白:$“${@/../…}”中的前导$是什么意思?
这里有个虫子。这是有效的语法,因为$“”在bash中有一个有用的含义(以英语文本的形式查找字符串,以查看是否有到当前用户的母语的翻译),但是没有合法的理由在这里执行翻译表查找。
为什么代码有危险的bug
有很多你需要逃离比空间,使一些安全壳评估!
假设您正在运行以下命令:
看起来很安全,对吧?但我们还是这么说吧
someuser
对他们的文件权限马虎(或恶意),有人这样做:哦,不!现在,如果您使用root权限运行该脚本,您将获得
/etc/shadow
发送到malicious.com
,让他们在空闲时尝试破解你的密码——而你问题中给出的代码也不会有帮助,因为它只反斜杠转义空格,而不是制表符或换行符,而且它对你没有任何作用$()
或者反记号或者其他可以控制shell的字符。正确的事情(选项1:使用标准数据)
一种安全而正确的方法可以转义要通过ssh传输的参数列表,如下所示:
这种方法有一些固有的局限性——特别是,它要求远程命令的stdin用于脚本内容——但是即使远程命令
/bin/sh
不支持bash扩展,例如$''
.正确的做法(选项2:使用python)
不像bash和ksh
printf %q
,python标准库的pipes.quote()
(在3.x中移动到shlex.quote()
)保证生成符合posix的输出。我们可以这样使用它: