清理用于更新脚本的输入

清理用于更新脚本的输入

查看一个 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
}

问题是注释是否包含中断sedmangles重击的字符。例如:

# 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

  1. '用。。。来代替'"'"'

为了sed

  1. 转义符&\/和行终止符。

或者会出现什么故障?


理想情况下,根本不会这样做,但好奇地想知道。

旁注:

另一个解决方案,将其保存在一个文件中,可能是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。

要消除该风险,您可以通过管道将curlto的输出手动删除 NULtr -d '\0'或 with

new_comment=${new_comment//$'\0'}

或者如果有这样的角色就退出:

[[ $new_comment = *$'\0'* ]] && die 'Something dodgy going on'

相关内容