转义shell脚本中的累积参数?

rlcwz9us  于 2023-08-07  发布在  Shell
关注(0)|答案(2)|浏览(109)

对于bug in git,此时git-submodule.sh读取(重新排序):

[iterating over command line arguments]
        --reference)
            case "$2" in '') usage ;; esac
            reference="--reference=$2"
            shift
            ;;
        --reference=*)
            reference="$1"
            shift
            ;;
[...]
        if test -n "$reference"
        then
            git-clone $quiet "$reference" -n "$url" "$path" --separate-git-dir "$gitdir"
        else
            git-clone $quiet -n "$url" "$path" --separate-git-dir "$gitdir"
        fi ||
        die "$(eval_gettext "Clone of '\$url' into submodule path '\$path' failed")"

字符串
这只使用--reference给出的 last 参数。现在我想增强这一点,以便将所有--reference选项传递给git-clone。这对于普通的参数(reference="$reference --reference=$2")来说是微不足道的,但是当我想到包含白色、引号或shell Meta字符的参数时,我的头脑会感到难以置信。
什么是避免这种累积争论的最佳实践?

hk8txs48

hk8txs481#

最佳实践是使用bash数组:

declare -a references
#...
  --reference)
    case ... esac
    references+=("--reference=$2")
    shift
    ;;
  --reference=*)
    references+=("$1")
    shift
    ;;
#...
# no need to test the array for emptiness
git-clone $quiet "${references[@]}" -n "$url" "$path" --separate-git-dir "$gitdir"

字符串
但是,引用的脚本使用/bin/sh。

gc0ot86w

gc0ot86w2#

在编写不能使用数组的可移植#!/bin/sh时,假设您实际上需要传递任意参数,最佳实践是在将参数中的每个单引号替换为'\''之后,用单引号(')字符 Package 每个参数。
假设你有一个名为quote_for_shell的函数,它允许你接受一个参数并完美地引用它。下面是该函数的最简单的未优化版本:

quote_for_shell()
{
    printf "'"
    printf '%s' "$1" | sed "s/'/'\\\\''/g"
    printf "'\n"
}

字符串
然后你可以这样做:

references=''
# ...
        --reference)
            case "$2" in '') usage ;; esac
            references="$references --reference=$(quote_for_shell "$2")"
            shift
            ;;
        --reference=*)
            references="$references $(quote_for_shell "$1")"
            shift
            ;;


但诀窍是,你不能只做git-clone $references(或git-clone "$references")-未加引号的变量/命令替换的结果不会被shell完全评估,它们只会对它们进行globbing和字段拆分(带引号的扩展也不会使用这些通道进行评估)。
所以你必须把这个命令 Package 在一个eval中,但是它**必须是得到eval 'ed的 * 引号 * 扩展,这样eval就能看到原始的空格和globbing字符,就像它们被转义一样:

eval "git-clone $quiet $references # !!!"


但是等等!同一个命令中的所有其他变量,可能包含任意字符,比如$url$path,现在也在eval中结束,所以它们现在也需要被转义:

url="$(quote_for_shell "$url")"
path="$(quote_for_shell "$path")"
gitdir="$(quote_for_shell "$gitdir")"
eval "git-clone $quiet $references $url $path --separate-git-dir $gitdir"

相关问题