bashshellparametersparameter-expansion

Expanding bash vars with spaces as arguments to bash function in scripts


Not critical - but I'm trying to get a deeper understanding of bash scripting and this is driving me crazy!

My goal - in a bash script:

No problem if there is no whitespace in $args - but here's a minimal script to illustrate:

#!/bin/bash
function tstArgs () {
    echo "In tstArgs: ArgCnt:$#; Arg1:[$1]; Arg2:[$2]"
}
ARG1=today
ARG2=tomorrow
CMD1="tstArgs $ARG1 $ARG2"
$CMD1 #Output - As Desired: In tstArgs: ArgCnt:2; Arg1:[today]; Arg2:[tomorrow]

ARGWS1="'today with spaces'"
ARGWS2="'tomorrow with spaces'"
CMD2="tstArgs $ARGWS1 $ARGWS2"
$CMD2 #Output: In tstArgs: ArgCnt:6; Arg1:[today]; Arg2:[with]

#The dream:
ARGARR=($ARGWS1 $ARGWS2)
CMD3="tstArgs ${ARGARR[@]}"
$CMD3 #Output: In tstArgs: ArgCnt:6; Arg1:[today]; Arg2:[with]
#ETC, ETC, ETC...

This doesn't show the COUNTLESS variations I tried - single quotes, double quotes, escaping quotes, changing IFS, using parameter escape operators ${ARG1@Q}, setting args w. echo XXX - and so much more - way too many to include here, but to be clear, I didn't just jump on stackoverflow without first spending HOURS.

Weirdly, I can use params w. whitespace if I call the function directly:

tstArgs $ARG1 $ARG2
#But no variation of anything like:
CMD="tstArgs $ARG1 $ARG2"
$CMD

I'm sure it must be possible, and probably simple - but it's some permutation I just haven't been able to crack.

Of course I can work around it - but I'm stubborn & persistent & hate to give up. If anyone has any insight, I'd be very grateful, and maybe even finally get some sleep...


Solution

  • Don't put arguments in a string. Put them in an array. Array elements handle spaces much more gracefully:

    declare -a ARGS
    ARGS+=( "today with spaces" )
    ARGS+=( "tomorrow with spaces" )
    CMD="tstArgs"
    ${CMD} "${ARGS[@]}"
    

    Alternatively:

    declare -a ARGS
    ARGS[0]="today with spaces"
    ARGS[1]="tomorrow with spaces"
    CMD="tstArgs"
    ${CMD} "${ARGS[@]}"
    

    Putting quotation marks around ${ARGS[@]} on the last line makes sure that each element of the array is quoted, thus preserving the spaces.