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 $1
dans $2
et laisse $1
null parce que la prochaine chose que je fais est soit le return
succè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 $2
dans $1:?
lequel va tuer un shell scripté et retourner une interruption à un interactif lors de l'écriture word
sur stderr.
Dans le second, getopts
les 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 getopts
tout ce qui est nécessaire, il faut développer eval
un ensemble OPTARG
dans l'affectation appropriée.
mktemp
si 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.