私は同様の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
まあ、どちらも同じテクニックをたくさん使っています。基本的に、シェル+
変数が設定されていない場合、それへの参照はパラメーター展開で展開されません。しかし、それが設定されている場合-その値に関係なく-次のようなパラメーター展開は、変数の値ではなく-に${parameter+word}
展開されword
ます。そして、シェル変数は成功すると自己テストし、自己置換します。
彼らはまた、自己失敗することができます。最上位の関数では、不正な名前が見つかった場合に移動$1
し$2
て$1
nullのままにします。これはreturn
、すべての引数が処理されてループが終了した場合に成功するか、引数が無効な場合にシェルが拡大$2
に$1:?
どのスクリプトシェルを殺し、書き込み中にインタラクティブなものに割り込みを返しますword
stderrに。
2つ目getopts
は割り当てを行います。そして、それは悪い名前を割り当てません-むしろそれを書くと標準エラーメッセージをstderrに書き出します。さらに、引数が最初にセット変数の名前であった$OPTARG
場合、argの値を保存します。したがって、getopts
必要なのは、適切な割り当てへのeval
セットOPTARG
の拡張です。
mktemp
あればそれがポータブル十分で、変数を割り当てる値、およびソースに一時ファイルの設定を解除します。シェル変数とは対照的に、少なくとも一時ファイルは多かれ少なかれ任意の名前で作成できます。