如何找出登录 shell 会话后设置的环境变量?
到目前为止,我的两个虚拟解决方案如下:
_VariableName1="VarValue1";export _VariableName1;
_VariableName2="VarValue2";export _VariableName2;
...
set | grep '_'
…这几乎显示了登录后设置的变量(与设置的变量.bash_profile
和不同的变量.bashrc
)。这种方法让我经常忘记变量中的下划线——工作中的老手们看到它时都会嘲笑我;)
第二种方法是使用“人类可读的变量”,但在登录后运行或sudo
:
su - username the
set > /tmp/vars.before
设置变量
VariableName1="VarValue1";export VariableName1;
VariableName2="VarValue2";export VariableName2;
set > /tmp/vars.after
...然后运行以下命令:
comm -13 /tmp/vars.before /tmp/vars.after
或者
comm --nocheck-order -3 /tmp/vars.before /tmp/vars.after
取决于comm
二进制等。
那么最干净、最聪明的找出答案的方法是什么?
答案1
一种方法是覆盖export
并unset
使用跟踪变量的函数。
请注意,要使此功能有效,您必须像这样导出变量:export <variable>=<value>
。
必须调用这两个函数export
并unset
在一个文件中维护一个变量列表,我将该文件命名为~/.track$$
($$
是您当前 shell 的 PID):
export ()
{
if echo $@ | egrep -q '[^=]+=[^=]+' && builtin export "$@" && echo $- | grep -q i; then # [1]
touch ~/.track$$ # [2]
cp -fa ~/{.track$$,.track$$.bak} 2> /dev/null; # [3]
grep -v "^$(echo $@ | sed 's/\([^=]=\).\+/\1/')" < ~/.track$$.bak > ~/.track$$ 2> /dev/null; # [4]
echo $@ >> ~/.track$$; # [5]
fi
}
unset ()
{
if builtin unset $@ && echo $- | grep -q i; then # [1]
touch ~/.track$$ # [2]
cp -fa ~/{.track$$,.track$$.bak} 2> /dev/null; # [3]
egrep -v "^$@=" < ~/.track$$.bak > ~/.track$$ 2> /dev/null; # [4]
fi
}
此外,您还需要找出您设置了哪些环境变量。像这样的别名将使其:
alias iset="cat ~/.track$$ 2>/dev/null"
像这样的别名:
alias ireset="rm ~/.track$$ >/dev/null 2>&1"
可用于重置列表。
为了将文件数量保持~/.track$$
在最低限度,我们可以使用这个管理命令:
rm $(ls -d ~/.* | egrep 'track[0-9]+$|track[0-9]+\.bak$' | egrep -v $(ps -ef | grep bash | grep -v grep | awk '{print $2}' | tr '\n' '|' | sed 's/|$//')) > /dev/null 2>&1
我们应该把这些函数、别名等放在哪里?
我建议你将函数、别名和管家命令添加到 的末尾~/.bashrc
,这样子 shell 也能获得这些函数。根据你的发行版以及 和 朋友的执行方式,/etc/profile
你/etc/bash.bashrc
可能过早地定义它们(在某些发行版~/.profile
源中~/.bashrc
或相反),因此你可能必须对其进行微调。
然后注销并重新登录。
现在,如果你export <variable>=<value>
在 bash 会话中运行该函数export
:
[1] 检查参数是否格式正确(这是为了避免在输入时出现虚假输入
export MYVAR
,因为其返回值为 0,并且会在 中创建一个条目~/.track$$
)[1] 然后执行
builtin export <variable>=<value>
(无论之后发生什么,都会设置变量)[1] 然后它会用 greps
$-
检查这是否是一个交互式 shell(参见这个答案)当我通过 ssh 进入 ubuntu 机器时,我使用的是什么类型的 shell[无耻的插件])。默认情况下,子 shell 不会继承函数,因此脚本不会创建~/.track$$
文件。但是,如果脚本使用#!/bin/bash -i
,则会创建文件。这将阻止它。[2] 然后它接触
~/.track$$
以确保它存在,并且[3] 制作备份
[4] 然后检查变量是否已经存在,如果是的话,就从中删除
~/.track$$
[5] 最后,它添加了一行
~/.track$$
类似地,如果你输入unset <variable>
并点击Enter该函数unset
:
[1] 执行
builtin unset <variable>
(无论之后发生什么,都会取消设置变量)[1] 如果
unset
成功,它会检查,如export
上面的函数所示。这是否是一个交互式的 shell(参见这个答案当我通过 ssh 进入 ubuntu 机器时,我使用的是什么类型的 shell[无耻的插件])。默认情况下,子 shell 不会继承函数,因此脚本不会创建~/.track$$
文件。但是,如果脚本使用#!/bin/bash -i
,则会创建文件。这将阻止它。[2] 然后它接触
~/.track$$
以确保它存在,并且[3] 然后制作
~/.track$$
[4] 从中删除变量条目
~/.track$$
builtin
我在这两个函数中使用的关键字是什么?由于export
或unset
都是 shell 内置命令(即 shell 自带的命令),因此我需要使用builtin
,它本身就是一个内置命令(来自man bash
):
内置 shell-builtin [参数]
执行指定的 shell 内置命令,向其传递参数,并返回其退出状态。这在定义名称与 shell 内置命令相同的函数时很有用,在函数中保留内置命令的功能。cd 内置命令通常以这种方式重新定义。如果 shell-builtin 不是 shell 内置命令,则返回状态为 false。
管理命令列出并过滤掉活动~/.track$$
文件并删除其余文件。
通过此设置您可以获得以下好处:
不再需要使用下划线。只需使用熟悉的
export
命令(已被函数覆盖)即可。每个
bash
会话都有自己的~/.track$$
文件。shell 之间不会发生冲突。作为上述副作用,子 shell 不会继承父级的
~/.track$$
文件,尽管它们继承了所有环境变量。在源文件中设置的环境变量(
. file
或source file
)被添加到~/.track$$
。在 () 子 shell 中设置的环境变量也会被(错误地)跟踪,因为
$$
它扩展为当前 shell 的进程 ID,而不是子 shell 的进程 ID(参见man bash
)。变量按从第一个到最后一个导出的顺序列出。
以及你设置的
.profile
其他脚本的变量重新分配(即使值相同)将由 列出iset
。例如,HOME
通常由 设定.profile
。如果您执行export HOME=/usr/local/bin:$HOME
并运行,iset
您将看到HOME
列出。
现在举一些例子:
导出的变量显示为
iset
:$ export MYVAR1=0987654321; iset MYVAR1=0987654321
重新定义的变量得到正确处理:
$ export MYVAR2="this is a string"; iset MYVAR1=0987654321 MYVAR2=this is a string $ export MYVAR2="this is a different string for the same variable"; iset MYVAR1=0987654321 MYVAR2=this is a different string for the same variable
环境根据
env
匹配iset
输出:$ env|grep MYVAR MYVAR2=this is a different string for the same variable MYVAR1=0987654321
只读变量不会添加到
~/.track$$
:$ export EUID=0; iset -bash: EUID: readonly variable MYVAR1=0987654321
~/.bashrc
执行时(例如,创建子 shell 时),旧的、不再使用的跟踪文件将被删除:$ ls -1 ~/.track* .track11002 .track11002.bak .track21774 .track21774.bak .track2923 .track2923.bak .track7382 .track7382.bak .track8374 .track8374.bak $ echo $$ 2923 $ bash <subshell>$ ls -1 ~/.track* .track2923 .track2923.bak
答案2
如果你有兴趣环境变量,你应该使用env
而不是set
。我不太确定我是否正确理解了你想要实现的目标,但似乎
env | sort > /tmp/vars.before
登录后,然后
env | sort > /tmp/vars.after
comm -13 /tmp/vars.before /tmp/vars.after
在稍后的某个时候,至少如果您的环境变量都不包含包含换行符的字符串,那么它会做正确的事情。(如果确实如此,我要么使用env -0 | sort -z
NULL 分隔环境变量,然后使用 perl 进行比较,要么用 perl 编写整个程序。)
答案3
如果您想知道已设置了哪些环境变量,只需输入以下命令:
printenv