Я написал аналогичную функцию POSIX, но это не рискует выполнить произвольный код:
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
Он также будет обрабатывать столько аргументов, сколько вы пожелаете предоставить. Если аргумент является допустимым именем, которое в противном случае уже не задано, оно игнорируется. Если аргумент является неправильным именем, он записывает в stderr и останавливается соответствующим образом, хотя любое действительное имя, предшествующее недопустимому в его командной строке, все равно будет обработано.
Я думал о другом способе. Мне это нравится намного лучше.
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
Хорошо, оба из них используют много тех же самых методов. В основном, если оболочка var не установлена, ссылка на нее не будет расширяться с +
расширением параметра. Но если он установлен - независимо от его значения - расширение параметра, подобное: ${parameter+word}
будет расширяться до word
-, а не до значения переменной. И так переменные оболочки самопроверка и подстановка на успех.
Они также могут потерпеть неудачу . В верхней функции, если найдено плохое имя, я вхожу $1
в ноль $2
и оставляю $1
ноль, потому что следующее, что я делаю, это либо return
успех, если все аргументы были обработаны и цикл заканчивается, либо, если аргумент был недействительным, оболочка будет разверните объект, $2
в $1:?
котором будет уничтожена сценарий оболочки и верните прерывание интерактивному при записи word
в stderr.
Во втором getopts
делает задания. И это не будет назначать плохое имя - скорее напишите, это напишет стандартное сообщение об ошибке в stderr. Более того, он сохраняет значение аргумента в том $OPTARG
случае, если аргумент был именем переменной набора в первую очередь. Таким образом, после выполнения getopts
все, что необходимо, это расширение eval
набора OPTARG
в соответствующее назначение.
mktemp
если что является портативным достаточно, и сбросить значение, и источник временный файл для присвоения переменной. По крайней мере временный файл может быть создан с более или менее произвольным именем в отличие от переменной оболочки.