on parsing arguments in shell

While most programming languages are accepting arguments as an array of strings, shell doesn’t

arglist.c

#include
int main(int argc, char **argv) {
int i;
for (i=1; argc>i; i++)
printf("$%d=%s\n",i,argv[i]);
}


$ make arglist
cc arglist.c -o arglist
$ ./arglist one two three four
$1=one
$2=two
$3=three
$4=four

To do the same in shell, it requires some dynamic evaluation, for instance with eval
arglist.sh

i=1
while [ $i -le $# ]
do
eval ARGV[$i]=\$$i
echo "\$$i=$(eval echo \"\${ARGV[$i]}\")"
((i+=1))
done


$ ./arglist.sh one two three four
$1=one
$2=two
$3=three
$4=four

To further send the arguments to another script or function, it is important to take consideration of white spaces and file expansion (e.g.: *.*), this is achieved with double-quotes and the at-sign

f "${ARGV[@]}"

I recommend against using eval whenever possible. While less awesome, I would prefer something more verbose and without eval
arglist2.sh

[ -n "$1" ] && echo "\$1=$1"
[ -n "$2" ] && echo "\$2=$2"
[ -n "$3" ] && echo "\$3=$3"
[ -n "$4" ] && echo "\$4=$4"
[ -n "$5" ] && echo "\$5=$5"


$ ./arglist2.sh one two three four
$1=one
$2=two
$3=three
$4=four

Using eval is difficult and dangerous. The innocent may messed up with the quotes resulting in random effects. It is also a common source of code injection
inj.sh

eval x=$1


$ ./inj.sh 1
$ ./inj.sh "1; echo uh-oh"
uh-oh

Ref: Eval Injection

2 thoughts on “on parsing arguments in shell

  1. David Grimberg

    You can avoid eval by using the shift operator:

    i=1
    while [ -n “$1” ]
    do
    echo \$$i=$1
    shift
    ((i+=1))
    done

    As an added benefit you can process more than nine (9) positional parameters by using the shift operator.

Comments are closed.