如何找出登录 shell 会话后设置的环境变量

如何找出登录 shell 会话后设置的环境变量

如何找出登录 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

一种方法是覆盖exportunset使用跟踪变量的函数。

请注意,要使此功能有效,您必须像这样导出变量:export <variable>=<value>

必须调用这两个函数exportunset在一个文件中维护一个变量列表,我将该文件命名为~/.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我在这两个函数中使用的关键字是什么?由于exportunset都是 shell 内置命令(即 shell 自带的命令),因此我需要使用builtin,它本身就是一个内置命令(来自man bash):

内置 shell-builtin [参数]

执行指定的 shell 内置命令,向其传递参数,并返回其退出状态。这在定义名称与 shell 内置命令相同的函数时很有用,在函数中保留内置命令的功能。cd 内置命令通常以这种方式重新定义。如果 shell-builtin 不是 shell 内置命令,则返回状态为 false。

管理命令列出并过滤掉活动~/.track$$文件并删除其余文件。

通过此设置您可以获得以下好处:

  • 不再需要使用下划线。只需使用熟悉的export命令(已被函数覆盖)即可。

  • 每个bash会话都有自己的~/.track$$文件。shell 之间不会发生冲突。

  • 作为上述副作用,子 shell 不会继承父级的~/.track$$文件,尽管它们继承了所有环境变量。

  • 在源文件中设置的环境变量(. filesource 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 -zNULL 分隔环境变量,然后使用 perl 进行比较,要么用 perl 编写整个程序。)

答案3

如果您想知道已设置了哪些环境变量,只需输入以下命令:

printenv

相关内容