# When to use eval

## Introduction

First and foremost: know what you're doing! Secondly, while you should avoid using `eval`, if its use makes for cleaner code, go ahead.

## Using Eval

For example, consider the following that sets the contents of `\$@` to the contents of a given variable:

``````a=(1 2 3)
eval set -- "\${a[@]}"
``````

This code is often accompanied by `getopt` or `getopts` to set `\$@` to the output of the aforementioned option parsers, however, you can also use it to create a simple `pop` function that can operate on variables silently and directly without having to store the result to the original variable:

``````isnum()
{
# is argument an integer?
local re='^[0-9]+\$'
if [[ -n \$1 ]]; then
[[ \$1 =~ \$re ]] && return 0
return 1
else
return 2
fi
}

isvar()
{
if isnum "\$1"; then
return 1
fi
local arr="\$(eval eval -- echo -n "\\$\$1")"
if [[ -n \${arr[@]} ]]; then
return 0
fi
return 1
}

pop()
{
if [[ -z \$@ ]]; then
return 1
fi

local var=
local isvar=0
local arr=()

if isvar "\$1"; then # let's check to see if this is a variable or just a bare array
var="\$1"
isvar=1
arr=(\$(eval eval -- echo -n "\\${\$1[@]}")) # if it is a var, get its contents
else
arr=(\$@)
fi

# we need to reverse the contents of \$@ so that we can shift
# the last element into nothingness
arr=(\$(awk <<<"\${arr[@]}" '{ for (i=NF; i>1; --i) printf("%s ",\$i); print \$1; }'

# set \$@ to \${arr[@]} so that we can run shift against it.
eval set -- "\${arr[@]}"

shift # remove the last element

# put the array back to its original order
arr=(\$(awk <<<"\$@" '{ for (i=NF; i>1; --i) printf("%s ",\$i); print \$1; }'

# echo the contents for the benefit of users and for bare arrays
echo "\${arr[@]}"

if ((isvar)); then
# set the contents of the original var to the new modified array
eval -- "\$var=(\${arr[@]})"
fi
}
``````

## Using Eval with Getopt

While eval may not be needed for a `pop` like function, it is however required whenever you use `getopt`:

Consider the following function that accepts `-h` as an option:

``````f()
{
local __me__="\${FUNCNAME}"
local argv="\$(getopt -o 'h' -n \$__me__ -- "\$@")"

eval set -- "\$argv"

while :; do
case "\$1" in
-h)
echo "LOLOLOLOL"
return 0
;;
--)
shift
break
;;
done

echo "\$@"
}
``````

Without `eval` `set -- "\$argv"` generates `-h --` instead of the desired `(-h --)` and subsequently enters an infinite loop because `-h --` doesn't match `--` or `-h`.

2017-06-02
2017-06-05
Bash Pedia
Icon