假设我导出了一个变量:
foo=bar
export foo
现在,我想取消导出它。也就是说,如果我这样做了,sh -c 'echo "$foo"'
我就不应该得到bar
.根本foo
不应该出现在sh -c
的环境中。
sh -c
仅仅是一个例子,一种显示变量存在的简单方法。该命令可以是任何东西 - 它的行为可能仅受其环境中变量的存在的影响。
我可以:
unset
变量,然后丢失它env
使用每个命令删除它:env -u foo sh -c 'echo "$foo"'
- 如果您想继续使用当前 shell 一段时间,这是不切实际的。
理想情况下,我希望保留变量的值,但根本不让它显示在子进程中,甚至不显示为空变量。
我想我可以这样做:
otherfoo="$foo"; unset foo; foo="$otherfoo"; unset otherfoo
otherfoo
如果 已经存在,则存在被踩踏的风险。
这是唯一的方法吗?有没有标准的方法?
答案1
没有标准方法。
您可以通过使用函数来避免使用临时变量。以下函数负责保持未设置的变量未设置和空变量为空。但是,它不支持某些 shell 中的功能,例如只读或类型化变量。
unexport () {
while [ "$#" -ne 0 ]; do
eval "set -- \"\${$1}\" \"\${$1+set}\" \"\$@\""
if [ -n "$2" ]; then
unset "$3"
eval "$3=\$1"
fi
shift; shift; shift
done
}
unexport foo bar
在 ksh、bash 和 zsh 中,您可以使用 .unexport 取消导出变量typeset +x foo
。这保留了特殊属性,例如类型,因此最好使用它。我认为所有具有typeset
内置功能的 shell 都有typeset +x
.
case $(LC_ALL=C type typeset 2>&1) in
typeset\ *\ builtin) unexport () { typeset +x -- "$@"; };;
*) unexport () { … };; # code above
esac
答案2
编辑:仅用于bash
,正如评论中指出的:
从每个给定名称中删除属性-n
的export
选项。export
(看help export
。)
所以为了bash
,你想要的命令是:export -n foo
答案3
我编写了一个类似的 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 变量自检并自替换成功。
他们还可以自我失败。在顶部函数中,如果发现错误的名称,我会进入$1
并$2
保留null,因为如果所有参数都已处理并且循环结束,$1
我要做的下一件事是成功,或者如果参数无效,shell 将return
展开其中$2
将$1:?
杀死脚本化 shell 并在写入时将中断返回到交互式 shellword
到标准错误。
在第二个中getopts
做作业。它不会指定一个错误的名称 - 而是 write 它将向 stderr 写出一条标准错误消息。更重要的是,它将 arg 的值保存在$OPTARG
如果参数首先是一个集合变量的名称。因此,完成所有操作后,getopts
需要将eval
setOPTARG
扩展为适当的赋值。