![清理用于更新脚本的输入](https://linux22.com/image/221742/%E6%B8%85%E7%90%86%E7%94%A8%E4%BA%8E%E6%9B%B4%E6%96%B0%E8%84%9A%E6%9C%AC%E7%9A%84%E8%BE%93%E5%85%A5.png)
查看一个 bash 脚本,该脚本从 Git 提交注释中获取输入来更新自身。简化:
script
:
#!/bin/bash
comment=''
printf '%s\n' "$comment"
upgrade_script() {
# Download latest:
curl -o updated_script https://path/to/file
# Get comment:
new_comment="$(curl https://path/to/comment)"
# Update comment='' with new_comment:
sed -i "3,0 s/comment=''/comment='$new_comment'/" updated_script
}
问题是注释是否包含中断sed
或mangles
重击的字符。例如:
# that's all she wrote! => comment='that's all she wrote!
# use /need/ over /want/ => s/comment=''/'use /need/ over /want'/'
当然,还有潜在的恶意但也有意想不到的事情,例如:
# Remove tmp files by: ' rm -r *;' => comment='Remove tmp files by: ' rm -r *;''
这足以解决这个问题吗?
在命令之前添加以下内容sed -i
:
new_comment=$(
sed \
-e "s/'/'\"'\"'/g" \
-e 's/[&\\/]/\\&/g; s/$/\\/; $s/\\$//'<<< "$new_comment"
)
为了bash
:
'
用。。。来代替'"'"'
。
为了sed
:
- 转义符
&
、\
、/
和行终止符。
或者会出现什么故障?
理想情况下,根本不会这样做,但好奇地想知道。
旁注:
另一个解决方案,将其保存在一个文件中,可能是exit
在脚本中添加 an 并在其后添加文本,然后使用sed
等来打印它。但这不是我的问题。
#!/bin/bash
code
code
code
# When in need of the comment:
sed -n '/^exit # EOF Script$/$ {/start_xyz/,/end_xyz/ ...}'
# or what ever. Could even record offset and byte-length safely
code
code
exit # EOF Script
start_xyz
Blah blah blah
blaah
end_xyz
想到这一点,我猜想:
comment=<<<'SOF'
...
SOF
只需更换任何一个SOF
即可避免过早结束。我的问题仍然是消毒多于。谢谢。
答案1
看来你需要结合:
所以:
#! /bin/bash -
comment=''
printf '%s\n' "$comment"
upgrade_script() {
local - new_comment quoted_for_sh quoted_for_sed_and_sh
set -o pipefail
# Get comment:
new_comment="$(curl https://path/to/comment)" || return
quoted_for_sh=\'${new_comment//\'/\'\\\'\'}\'
quoted_for_sed_and_sh=$(
printf '%s\n' "$quoted_for_sh" |
LC_ALL=C sed 's:[\\/&]:\\&:g;$!s/$/\\/'
) || return
curl https://path/to/file |
# Update comment='' with new_comment:
LC_ALL=C sed "3s/comment=''/comment=$quoted_for_sed/" > updated_script
}
虽然 zsh+perl 比 bash+sed 是更好的选择:
#! /bin/zsh -
comment=''
print -r -- $comment
upgrade_script() {
set -o localoptions -o pipefail
local new_comment quoted_for_sh
# Get comment:
new_comment=$(curl https://path/to/comment) || return
quoted_for_sh=${(qq)new_comment}
curl https://path/to/file |
# Update comment='' with new_comment:
perl -pse "s/comment=\K''/$repl/ if $. == 3
' -- -repl=$quoted_for_sh > updated_script
}
请记住,comment
最终可能包含一个 NUL 字符,这对于 zsh 及其内置函数或函数来说很好,但不能作为参数传递给外部命令。bash
删除$(...)
NUL。
要消除该风险,您可以通过管道将curl
to的输出手动删除 NULtr -d '\0'
或 with
new_comment=${new_comment//$'\0'}
或者如果有这样的角色就退出:
[[ $new_comment = *$'\0'* ]] && die 'Something dodgy going on'