我写了一个类似的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
嗯,这两个都使用了很多相同的技术。基本上,如果未设置shell var,则对其的引用将不会通过+
参数扩展来扩展。但是,如果将其设置-无论其值如何-像这样的参数扩展:${parameter+word}
都会扩展为word
-而不是变量的值。因此,shell变量在成功时会进行自我测试和自我替代。
他们也可以自我失败。在top函数中,如果发现了一个不好的名字,我$1
进入$2
并保留为$1
null,因为return
如果所有的args已被处理且循环结束,那么我接下来要做的就是成功,或者如果arg无效,则shell将执行扩展$2
到$1:?
其中将杀死脚本化的shell,并在写入word
stderr 时将中断返回给交互式中断。
在第二个getopts
中,分配作业。而且它不会分配一个错误的名称-而是写它会向stderr写出标准错误消息。此外,$OPTARG
如果参数首先是set变量的名称,它将保存arg的值。因此,在完成getopts
所有之后,需要将eval
集合OPTARG
扩展为适当的分配。
mktemp
如果可以移植的话,可以使用它,并取消设置该值,并获取临时文件以分配变量。与shell变量相比,至少可以使用或多或少的任意名称创建一个临时文件。