Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to (not) pass empty quoted variables as arguments to commands

Tags:

bash

shell

I have a function in a bash script that looks like this (simplified):

# 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}"
}

It can be called like f http://example.com/resource or f http://example.com/resource p1=v1 p2=v2. The problem is when DATA_OPTION and PARAMS are empty. In this case, Bash passes two empty arguments to curl, which are then recognised as URLs by curl and produce the following ugly message:

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

I temporarily solved the problem using an if/else so that DATA_OPTION and PARAMS are not passed at all:

    [..]

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

but this seems ugly to me. Is there a more elegant solution? Note that the quotes around PARAMS are needed because some parameter values may contain spaces.

like image 602
konikos Avatar asked Nov 30 '13 23:11

konikos


Video Answer


1 Answers

You can actually solve this cleanly with the "use alternate value" option (:+) in a parameter expansion:

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

If PARAMS is empty or undefined, the whole ${PARAMS:+"--data" "$PARAMS"} thing evaluates to the empty string, and since it's not double-quoted, word splitting removes it entirely. On the other hand, if PARAMS is nonblank, it gets effectively replaced by "--data" "$PARAMS", which is exactly what you want.

like image 190
Gordon Davisson Avatar answered Nov 02 '22 00:11

Gordon Davisson