J'ai écrit une fonction POSIX similaire, mais cela ne risque pas d'exécuter du code arbitraire:
unexport()
while case ${1##[0-9]*} in ### rule out leading numerics
(*[!_[:alnum:]]*|"") ### filter out bad|empty names
set "" ${1+"bad name: '$1'"} ### prep bad name error
return ${2+${1:?"$2"}} ### fail w/ above err or return
esac
do eval set '"$'"{$1+$1}"'" "$'"$1"'" "$'@\" ### $1 = ( $1+ ? $1 : "" )
eval "${1:+unset $1;$1=\$2;} shift 3" ### $$1 = ( $1:+ ? $2 : -- )
done
Il traitera également autant d'arguments que vous voudrez le fournir. Si un argument est un nom valide qui n'est pas déjà défini autrement, il est ignoré en silence. Si un argument est un mauvais nom, il écrit dans stderr et s'arrête comme il convient, bien que tout nom valide précédant un invalide sur sa ligne de commande soit toujours traité.
J'ai pensé à une autre façon. Je l'aime beaucoup mieux.
unexport()
while unset OPTARG; OPTIND=1 ### always work w/ $1
case ${1##[0-9]*} in ### same old same old
(*[!_[:alnum:]]*|"") ### goodname && $# > 0 || break
${1+"getopts"} : "$1" ### $# ? getopts : ":"
return ### getopts errored or ":" didnt
esac
do eval getopts :s: '"$1" -"${'"$1+s}-\$$1\""
eval unset "$1; ${OPTARG+$1=\${OPTARG}#-}"
shift
done
Eh bien, les deux utilisent beaucoup des mêmes techniques. Fondamentalement, si une var shell n'est pas définie, une référence à celle-ci ne se développera pas avec une +expansion de paramètre. Mais s'il est défini - quelle que soit sa valeur - une expansion de paramètre comme: ${parameter+word}s'étendra à word- et non à la valeur de la variable. Et donc les variables shell s'auto-testent et se remplacent elles-mêmes en cas de succès.
Ils peuvent également échouer . Dans la fonction supérieure, si un mauvais nom est trouvé, je passe $1dans $2et laisse $1null parce que la prochaine chose que je fais est soit le returnsuccès si tous les arguments ont été traités et la boucle est terminée, soit, si l'argument n'était pas valide, le shell développez le $2dans $1:?lequel va tuer un shell scripté et retourner une interruption à un interactif lors de l'écriture wordsur stderr.
Dans le second, getoptsles affectations sont effectuées. Et il n'attribuera pas de mauvais nom - plutôt, il écrira un message d'erreur standard à stderr. De plus, il enregistre la valeur de l'argument $OPTARG si l'argument était le nom d'une variable définie en premier lieu. Donc, après avoir fait getoptstout ce qui est nécessaire, il faut développer evalun ensemble OPTARGdans l'affectation appropriée.
mktempsi cela est suffisamment portable, annuler la valeur et source le fichier temporaire pour affecter la variable. Au moins un fichier temporaire peut être créé avec un nom plus ou moins arbitraire contrairement à une variable shell.