Bash
Wanneer eval gebruiken?
Zoeken…
Invoering
Eerst en vooral: weet wat je doet! Ten tweede, als je eval
zou moeten vermijden, als het gebruik ervan schonere code oplevert, ga je gang.
Eval gebruiken
Overweeg bijvoorbeeld het volgende dat de inhoud van $@
instelt op de inhoud van een gegeven variabele:
a=(1 2 3)
eval set -- "${a[@]}"
Deze code gaat vaak gepaard met getopt
of getopts
om $@
te stellen op de uitvoer van de bovengenoemde optieparsers, maar u kunt het ook gebruiken om een eenvoudige pop
functie te maken die stil en direct op variabelen kan werken zonder het resultaat op te slaan om de originele variabele:
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
}
Eval gebruiken met Getopt
Hoewel eval misschien niet nodig is voor een pop
achtige functie, is het echter wel vereist wanneer je getopt
:
Overweeg de volgende functie die -h
als optie accepteert:
f()
{
local __me__="${FUNCNAME[0]}"
local argv="$(getopt -o 'h' -n $__me__ -- "$@")"
eval set -- "$argv"
while :; do
case "$1" in
-h)
echo "LOLOLOLOL"
return 0
;;
--)
shift
break
;;
done
echo "$@"
}
Zonder eval
set -- "$argv"
genereert -h --
plaats van de gewenste (-h --)
en komt vervolgens in een oneindige lus omdat -h --
niet overeenkomt --
of -h
.