Bash
När man ska använda eval
Sök…
Introduktion
Först och främst: vet vad du gör! För det andra, medan du bör undvika att använda eval
, eval
om du använder det för renare kod.
Med hjälp av Eval
Tänk till exempel på följande som ställer in innehållet i $@
till innehållet i en given variabel:
a=(1 2 3)
eval set -- "${a[@]}"
Den här koden åtföljs ofta av getopt
eller getopts
att ställa $@
till utgången från de ovannämnda tillvalsparserserna, men du kan också använda den för att skapa en enkel pop
som kan fungera på variabler tyst och direkt utan att behöva lagra resultatet för den ursprungliga variabeln:
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
}
Använda Eval med Getopt
Även om eval kanske inte behövs för en pop
funktion, krävs det dock när du använder getopt
:
Tänk på följande funktion som accepterar -h
som ett alternativ:
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 "$@"
}
Utan eval
set -- "$argv"
genererar -h --
istället för det önskade (-h --)
och går därefter in i en oändlig slinga eftersom -h --
inte matchar --
eller -h
.