如何读取和设置 Linux 环境变量和 Shell 变量

介绍

当您通过 shell 会话与服务器进行交互时, shell 会收集许多信息来确定其行为和访问资源,其中一些设置包含在配置设置中,另一些则由用户输入决定。

壳跟踪所有这些设置和细节的一种方式是通过它所维护的区域称为 环境. 环境是壳每次开始会话时构建的区域,该区域包含定义系统属性的变量。

在本指南中,我们将讨论如何与环境互动,并通过配置文件和互动方式读取或设置环境和壳变量。

如果您想使用本地系统或远程服务器跟进,请打开终端并在那里运行本教程中的命令。

环境和环境变量如何工作

每个 shell 会话发生时,都会有一个过程来收集和编译信息,这些信息应该可用于 shell 过程和其子过程,它会从系统上各种不同的文件和设置中获取这些设置的数据。

环境提供了一个媒介,通过它壳过程可以获得或设置设置,并反过来将这些传递给其子过程。

环境是以代表关键值对的字符串来实现的。如果传递了多个值,它们通常是由结(:)字符分开的。

1KEY=value1:value2:...

如果值包含显著的白色空间,则使用报价:

1KEY="value with spaces"

这些场景中的关键是变量,它们可以是两种类型的一个,环境变量或壳变量。

环境变量是当前壳定义的变量,由任何子壳或过程继承。

** Shell 变量** 是仅包含在其被设置或定义的 shell 中的变量,通常用于跟踪实时数据,例如当前工作目录。

根据惯例,这些类型的变量通常用所有大写字母来定义,这有助于用户在其他情况下区分环境变量。

打印壳和环境变量

每个 shell 会话都跟踪其自己的 shell 和环境变量,我们可以通过几种不同的方式访问这些变量。

我们可以通过使用envprintenv命令查看我们所有环境变量的列表,在它们的默认状态下,它们应该完全相同:

1printenv

您的壳环境可能具有多或少的变量集,其值与以下输出不同:

 1[secondary_label Output]
 2SHELL=/bin/bash
 3TERM=xterm
 4USER=demouser
 5LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca:...
 6MAIL=/var/mail/demouser
 7PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
 8PWD=/home/demouser
 9LANG=en_US.UTF-8
10SHLVL=1
11HOME=/home/demouser
12LOGNAME=demouser
13LESSOPEN=| /usr/bin/lesspipe %s
14LESSCLOSE=/usr/bin/lesspipe %s %s
15_=/usr/bin/printenv

这对于printenvenv的输出来说是相当典型的。这两个命令之间的差异只在其更具体的功能上显而易见。例如,在printenv中,你可以要求单个变量的值:

1printenv PATH
1[secondary_label Output]
2/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

另一方面,‘env’允许您通过将一组变量定义传递到这样的命令来修改程序运行的环境:

1env VAR1="value" command_to_run command_options

由于,正如我们上面所学到的,儿童过程通常会继承父母过程的环境变量,这使您有机会替代值或为孩子添加额外的变量。

正如您可以从我们的printenv命令的输出中看到的,没有我们的输入,通过我们的系统文件和流程设置了相当少量的环境变量。

这些显示了环境变量,但我们如何看到壳变量?

如果我们在没有任何额外参数的情况下输入设置,我们将获得所有壳变量,环境变量,本地变量和壳函数的列表:

1set
1[secondary_label Output]
2BASH=/bin/bash
3BASHOPTS=checkwinsize:cmdhist:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:login_shell:progcomp:promptvars:sourcepath
4BASH_ALIASES=()
5BASH_ARGC=()
6BASH_ARGV=()
7BASH_CMDS=()
8. . .

這通常是一個巨大的清單,你可能想將它插入一個頁面程式,以便更容易處理輸出量:

1set | less

我们收到的额外信息量有点压倒性,我们可能不需要知道定义的所有 bash 函数。

我们可以通过指定设置应该在POSIX模式中工作来清理输出,这不会打印壳函数,我们可以在子壳中执行,以便它不会改变我们的当前环境:

1(set -o posix; set)

这将列出所定义的所有环境和壳变量。

我们可以尝试将此输出与envprintenv命令的输出进行比较,以便尝试获得只包含壳变量的列表,但这会因为这些命令输出信息的不同方式而不完美:

1comm -23 <(set -o posix; set | sort) <(env | sort)

这可能仍然包括一些环境变量,因为设置命令输出引用值,而printenvenv命令不引用字符串的值。

这仍然应该给您一个很好的想法,环境和壳变量设置在您的会话。

这些变量用于各种事物,它们提供了一个替代的方式来为过程之间的会话设置持久值,而不写文件的更改。

共同的环境和壳变量

一些环境和壳变量非常有用,并且经常被引用。 以下是您会遇到的一些常见环境变量:

  • `SHELL':此描述将解释您输入的任何命令的外壳。 在大多数情况下, 默认会被击出, 但是如果您喜欢其他选项, 其他的值可以设定 。
  • `TERM': 此指定在运行 shell 时要模拟的终端类型 。 不同的硬件终端可以为不同的操作需要而相仿. 你通常不需要担心这个
  • USER':当前登录用户. *PWD':当前工作目录. *OLDPWD':上一个工作目录. 这个由 shell 保存, 以便通过运行 cd - ` 来切换到您的上一个目录 。
  • LS_ COLORS' : 定义了用于在 ls 命令中选择性地添加彩色输出的颜色代码 。 这用于区分不同的文件类型,并给用户一个一目了然提供更多的信息. *'MIL':目前用户邮箱的路径. *PATH':系统在查找命令时会检查的目录列表. 当用户在命令中键入时,系统会在此顺序检查目录中可执行文件.
  • LANG:当前语言和本地化设置,包括字符编码。 *'HOME':当前用户的家目录.
  • _ : 最近执行的命令 。 (英语)

除了这些环境变量外,您经常看到的一些壳变量是:

  • BASHOPTS':在实施殴打时使用的选项清单。 这可以用来发现外壳环境是否会以你想要的方式运行. *BASH-VERSION':正在以人可读的形式执行的被打的版本。 *`BASH_VERSINFO':以机器可读输出的bash版本.
  • COLUMNS:用于绘制屏幕输出的宽列数。 *DIRSTACK':带有pushd'和pod'命令的目录堆栈。 *HISTFILESIZE':存储到文件中的命令历史行数. *`HISTSIZE':内存中允许的命令历史行数.
  • "HOSTNAME":此时计算机的主机名.
  • IFS':命令行上要分开输入的内部字段分隔符. 默认,这是一个空间。 *PS1':主命令即时定义. 用于定义您启动 shell 会话时的提示长相 。 PS2'用于宣布命令跨越多行时的次要提示。 *SHELLOPTS':可设置为`set'选项的壳牌选项。
  • ‘UID':当前用户的UID. (英语)

设置壳和环境变量

为了更好地理解壳和环境变量之间的区别,并介绍设置这些变量的语法,我们将做一个小型演示。

创建 Shell 变量

我们将从当前会话中定义一个壳变量开始,这是很容易实现的;我们只需要指定一个名称和一个值。

1TEST_VAR='Hello World!'

在这里,我们已经使用了引文,因为我们变量的值包含一个空间,此外,我们已经使用了单个引文,因为呼声点是 bash shell 中的一个特殊字符,如果它没有逃脱或放入单个引文,则通常会扩展到 bash 历史。

我们现在有一个壳变量,这个变量在我们当前的会话中可用,但不会被转移到儿童过程中。

我们可以通过在设置输出中抓住我们的新变量来看到这一点:

1set | grep TEST_VAR
1[secondary_label Output]
2TEST_VAR='Hello World!'

我们可以通过尝试使用printenv来验证这不是一个环境变量:

1printenv | grep TEST_VAR

无需返回输出。

让我们以此作为一个机会来展示一种方法来访问任何壳或环境变量的价值。

1echo $TEST_VAR
1[secondary_label Output]
2Hello World!

正如你所看到的,通过使用一个$符号来引用变量的值,壳就意味着它应该取代变量的值,当它碰到这一点时。

所以现在我们有一个壳变量. 它不应该被传递给任何儿童过程. 我们可以从我们当前的壳中生成一个 new bash shell,以示范:

1bash
2echo $TEST_VAR

如果我们键入bash来生出一个孩子的壳,然后尝试访问变量的内容,什么都不会返回。

返回我们的原始壳,输入退出:

1exit

创建环境变量

现在,让我们将我们的壳变量转化为环境变量,我们可以通过 exporting 变量来做到这一点。

1export TEST_VAR

这将使我们的变量变成环境变量,我们可以通过再次检查我们的环境清单来验证这一点:

1printenv | grep TEST_VAR
1[secondary_label Output]
2TEST_VAR=Hello World!

这一次,我们的变量出现了,让我们再试试我们的婴儿壳实验:

1bash
2echo $TEST_VAR
1[secondary_label Output]
2Hello World!

很棒!我们的儿童壳已收到其父母设置的变量。在我们离开这个儿童壳之前,让我们试着导出另一个变量。我们可以在这样一个单一步骤中设置环境变量:

1export NEW_VAR="Testing export"

测试它是否被导出为环境变量:

1printenv | grep NEW_VAR
1[secondary_label Output]
2NEW_VAR=Testing export

现在,让我们回到我们的原始壳:

1exit

让我们看看我们的新变量是否可用:

1echo $NEW_VAR

没有什么被返回。

这是因为环境变量仅传递给儿童流程. 没有内置的方式来设置父母壳的环境变量. 这在大多数情况下是好的,并防止程序影响它们被调用的操作环境。

NEW_VAR变量被设置为我们的儿童壳中的环境变量. 这个变量将可用于它自己和其任何的儿童壳和过程。

删除和删除变量

我们仍然有我们的 TEST_VAR 变量被定义为环境变量,我们可以通过键入将其转换为壳变量:

1export -n TEST_VAR

它不再是环境变量:

1printenv | grep TEST_VAR

然而,它仍然是一个壳变量:

1set | grep TEST_VAR
1[secondary_label Output]
2TEST_VAR='Hello World!'

如果我们想完全取消变量,无论是壳或环境,我们可以用启动命令做到这一点:

1unset TEST_VAR

我们可以检查它不再设置:

1echo $TEST_VAR

没有返回,因为变量已被删除。

在 Login 中设置环境变量

我们已经提到,许多程序使用环境变量来决定如何操作的具体情况,我们不希望每次我们开始一个新的壳会话时都需要设置重要变量,我们已经看到登录时已经设置了多少变量,所以我们如何自动创建和定义变量?

事实上,这是一个比起初看起来更复杂的问题,因为bash壳读取的许多配置文件取决于它是如何启动的。

登录、非登录、互动和非互动壳会话的区别

bash shell 读取不同的配置文件,取决于会话是如何开始的。

不同会话之间的区别之一是,壳是否被生成为 loginnon-login会话。

一个 login shell 是一个 shell 会话,从验证用户开始. 如果您登录到终端会话或通过 SSH 进行验证,您的 shell 会话将被设置为登录 shell。

如果您从您身份验证的会话中开始一个新的 shell 会话,就像我们从终端调用bash命令一样,将启动一个 non-login shell 会话。

另一个可以区分的区别是壳会话是互动的还是非互动的。

一个 ** 互动** shell 会话是连接到终端的 shell 会话,一个 ** 非互动** shell 会话是没有连接到终端会话的。

因此,每个壳会话都分为登录或非登录,互动或非互动。

通常以 SSH 开始的正常会话通常是交互式登录壳. 从命令行运行的脚本通常在非交互式,非登录壳中运行。

是否将 shell 会话归类为登录或非登录 shell 有影响哪些文件被读取以初始化 shell 会话。

作为登录会话开始的会话将首先从/etc/profile文件中阅读配置详细信息,然后在用户主目录中搜索第一个登录壳配置文件,以获取用户特定的配置详细信息。

它读取了它可以查找的第一个文件 ~/.bash_profile, ~/.bash_login,和 ~/.profile,并且不会读取任何进一步的文件。

相反,定义为非登录壳的会话会读取/etc/bash.bashrc,然后读取用户特定的~/.bashrc文件来构建其环境。

非交互式壳读取名为BASH_ENV的环境变量,并读取指定的文件来定义新环境。

实施环境变量

正如你所看到的,有各种不同的文件,我们通常需要查看我们的设置。

这提供了大量的灵活性,可以在特定情况下帮助我们想要登录壳中的某些设置,以及非登录壳中的其他设置。

幸运的是,大多数Linux发行版都将登录配置文件配置为非登录配置文件。这意味着你可以在非登录配置文件中定义所需的环境变量。

我们通常会设置用户特定的环境变量,我们通常会希望我们的设置在登录和非登录壳中可用。

现在打开此文件:

1nano ~/.bashrc

这里的大多数定义都用于设置 bash 选项,这些选项与环境变量无关。

1export VARNAME=value

任何新的环境变量都可以在 `~/.bashrc 文件中添加到任何地方,只要它们不放在另一个命令或循环的中间。我们可以保存和关闭该文件。

1source ~/.bashrc

如果您需要设置整个系统的变量,您可能想考虑将它们添加到 /etc/profile/etc/bash.bashrc/etc/environment

结论

环境和壳变量在您的壳会话中始终存在,可以非常有用,它们是家长过程为孩子设置配置细节的一个有趣的方式,也是设置文件之外的选项的一种方式。

例如,一些部署机制依赖环境变量来配置身份验证信息,这是有用的,因为它不需要将这些信息保存在外部方可看到的文件中。

有许多其他,更平凡,但更常见的场景,您需要阅读或改变您的系统环境. 这些工具和技术应该为您提供一个良好的基础,以做出这些更改并正确使用它们。

Published At
Categories with 技术
comments powered by Disqus