shell 如何(不)将带引号的空变量作为参数传递给命令

lpwwtiir  于 2023-01-09  发布在  Shell
关注(0)|答案(3)|浏览(174)

我在bash脚本中有一个函数,如下所示(简化):

# Usage: f URL [PARAMETER]...
f() {
    local URL="$1"; shift

    local PARAMS
    for arg in "$@"; do
        PARAMS="${PARAMS}&${arg}"
    done
    PARAMS="${PARAMS#'&'}"

    local DATA_OPTION
    [ -z "${PARAMS}" ] || DATA_OPTION='--data'

    curl -o - "${DATA_OPTION}" "${PARAMS}" "${URL}"
}

它可以像f http://example.com/resourcef http://example.com/resource p1=v1 p2=v2那样调用,问题是当DATA_OPTIONPARAMS为空时,在这种情况下,Bash将两个空参数传递给curl,curl随后将其识别为URL,并生成以下丑陋的消息:

curl: (3) <url> malformed
curl: (3) <url> malformed

我使用if/else临时解决了这个问题,因此DATA_OPTIONPARAMS根本不被传递:

[..]

    if [ -z "${PARAMS}" ]; then
        curl -o - --data "${PARAMS}" "${URL}"
    else
        curl -o - "${URL}"
    fi
}

但这对我来说似乎很难。有更优雅的解决方案吗?注意,需要在PARAMS周围加上引号,因为一些参数值可能包含空格。

bzzcjhmw

bzzcjhmw1#

实际上,您可以使用参数扩展中的“use alternate value”选项(:+)来干净地解决这个问题:

curl -o - ${PARAMS:+"--data" "$PARAMS"} "${URL}"

如果PARAMS为空或未定义,则整个${PARAMS:+"--data" "$PARAMS"}的值为空字符串,并且由于它不是双引号,单词拆分会将其完全删除;另一方面,如果PARAMS为非空,则它实际上会被"--data" "$PARAMS"替换,这正是您想要的。
[EDIT]这可以在大多数POSIX风格的shell中使用,但不能在zsh中使用,因为zsh不会对扩展进行单词分割,即使扩展没有引号。如果你想在zsh(以及bash、dash、ksh等)中使用,你需要将选项标签设置为一个单独的条件项:

curl -o - ${PARAMS:+"--data"} ${PARAMS:+"$PARAMS"} "${URL}"
j9per5c4

j9per5c42#

我觉得这是慵懒与优雅的完美结合:

curl -o - --data "&$PARAMS" "$URL"

是的,这里有一个无用的&,问题是它不会伤害任何人,它很短,而且它应该对你的两种情况都有效,不管你在PARAMS中有没有任何东西。

aydmsdu9

aydmsdu93#

使用bash数组生成命令

为此我经常使用bash数组!
注意,使用IFS='&'合并参数与&是更快和更简单!
您的功能将变为:

f() {
    local cmdArgs=(-o -) Url="$1" IFS='&'
    shift
    [[ $* ]] && cmdArgs+=(--data "$*")
    curl "${cmdArgs[@]}" $Url
}

注意:避免使用大写的变量名!最好使用驼峰式的小写!

相关问题