Linux

关注公众号 jb51net

关闭
首页 > 网站技巧 > 服务器 > Linux > Linux设置环境和shell变量

Linux上读取或设置环境和shell变量的教程

作者:白如意i

当通过 shell 会话与服务器交互时,有许多信息会被 shell 编译以确定其行为和对资源的访问,其中一些设置包含在配置设置中,而其他一些则由用户输入确定,在本指南中,我们将讨论如何与环境进行交互,并通过配置文件以及交互方式读取或设置环境和 shell 变量

简介

当通过 shell 会话与服务器交互时,有许多信息会被 shell 编译以确定其行为和对资源的访问。其中一些设置包含在配置设置中,而其他一些则由用户输入确定。

Shell 跟踪所有这些设置和详细信息的一种方式是通过它维护的一个称为环境的区域。环境是 shell 每次启动会话时构建的一个区域,其中包含定义系统属性的变量。

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

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

环境和环境变量的工作原理

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

环境提供了一个介质,通过它,shell 进程可以获取或设置设置,并将这些传递给其子进程。

环境被实现为表示键值对的字符串。如果传递了多个值,它们通常由冒号(:)字符分隔。每对通常看起来像这样:

KEY=value1:value2:...

如果值包含重要的空格,则使用引号:

KEY="带有空格的值"

这些情况下的键是变量。它们可以是环境变量或 shell 变量中的一种。

环境变量是为当前 shell 定义的变量,并且会被任何子 shell 或进程继承。环境变量用于将信息传递给从 shell 生成的进程。

Shell 变量是仅包含在设置或定义它们的 shell 中的变量。它们通常用于跟踪短暂数据,比如当前工作目录。

按照惯例,这些类型的变量通常使用全大写字母定义。这有助于用户在其他上下文中区分环境变量。

打印 Shell 和环境变量

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

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

printenv

您的 shell 环境可能设置了更多或更少的变量,并且具有不同的值,如下所示:

SHELL=/bin/bash
TERM=xterm
USER=demouser
LS_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:...
MAIL=/var/mail/demouser
PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
PWD=/home/demouser
LANG=en_US.UTF-8
SHLVL=1
HOME=/home/demouser
LOGNAME=demouser
LESSOPEN=| /usr/bin/lesspipe %s
LESSCLOSE=/usr/bin/lesspipe %s %s
_=/usr/bin/printenv

这在 printenv 和 env 的输出中是相当典型的。这两个命令之间的区别只在它们更具体的功能上才会显现。例如,使用 printenv,您可以请求单个变量的值:

printenv PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

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

env VAR1="value" command_to_run command_options

由于,正如我们上面了解的那样,子进程通常会继承父进程的环境变量,这使您有机会覆盖值或为子进程添加额外的变量。

从我们的 printenv 命令的输出中可以看出,系统文件和进程已经设置了相当多的环境变量,而无需我们的输入。

这些显示了环境变量,但我们如何查看 shell 变量呢?

set 命令可以用于此目的。如果我们不带任何额外参数地输入 set,我们将得到所有 shell 变量、环境变量、本地变量和 shell 函数的列表:

set
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:login_shell:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
. . .

这通常是一个庞大的列表。您可能希望将其传输到一个分页程序中,以更轻松地处理输出的数量:

set | less

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

我们可以通过指定 set 应该在 POSIX 模式下运行来清理输出,这样就不会打印 shell 函数。我们可以在子 shell 中执行此操作,以便不更改当前环境:

(set -o posix; set)

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

我们可以尝试将此输出与 env 或 printenv 命令的输出进行比较,以尝试获取仅 shell 变量的列表,但由于这些命令输出信息的方式不同,这将是不完美的:

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

由于 set 命令输出带引号的值,而 printenv 和 env 命令不引用字符串的值,这可能仍然会包括一些环境变量。

这仍然应该给您一个关于在您的会话中设置的环境和 shell 变量的很好的概念。

这些变量用于各种事情。它们提供了一种在进程之间设置持久值的替代方式,而无需将更改写入文件。

常见的环境变量和 Shell 变量

一些环境变量和 Shell 变量非常有用,经常被引

除了这些环境变量之外,你经常会看到一些 shell 变量,例如:

设置 Shell 和环境变量

用。以下是一些你经常会遇到的常见环境变量:

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

创建 Shell 变量

我们将从在当前会话中定义一个 shell 变量开始。这很容易实现;我们只需要指定一个名称和一个值。我们将遵循变量名称全大写的约定,并将其设置为一个简单的字符串。

TEST_VAR='Hello World!'

在这里,我们使用引号,因为变量的值包含空格。此外,我们使用单引号,因为感叹号是 bash shell 中的特殊字符,如果不转义或放入单引号中,它通常会扩展为 bash 历史记录。

现在我们有了一个 shell 变量。这个变量在当前会话中可用,但不会传递给子进程。

我们可以通过在 set 输出中查找我们的新变量来验证这一点:

set | grep TEST_VAR
TEST_VAR='Hello World!'

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

printenv | grep TEST_VAR

不应返回任何输出。

让我们利用这个机会演示访问任何 shell 或环境变量的值的一种方法。

echo $TEST_VAR
Hello World!

如你所见,通过在变量前加上 $ 符号来引用变量的值。shell 会在遇到这个符号时替换变量的值。

现在我们有了一个 shell 变量。它不应该传递给任何子进程。我们可以从当前 shell 中生成一个新的 bash shell来演示:

bash
echo $TEST_VAR

如果我们输入 bash 生成一个子 shell,然后尝试访问变量的内容,将不会返回任何内容。这是我们预期的结果。

通过输入 exit 返回到我们的原始 shell:

exit

创建环境变量

现在,让我们将我们的 shell 变量转换为环境变量。我们可以通过导出变量来实现这一点。相应的命令是:

export TEST_VAR

这将把我们的变量变成环境变量。我们可以通过再次检查我们的环境列表来验证这一点:

printenv | grep TEST_VAR
TEST_VAR=Hello World!

这次,我们的变量显示出来了。让我们再次尝试在我们的子 shell 中进行实验:

bash
echo $TEST_VAR
Hello World!

太棒了!我们的子 shell 已经接收到了由其父级设置的变量。在我们退出这个子 shell 之前,让我们尝试导出另一个变量。我们可以像这样一步设置环境变量:

export NEW_VAR="Testing export"

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

printenv | grep NEW_VAR
NEW_VAR=Testing export

现在,让我们退出回到我们的原始 shell:

exit

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

echo $NEW_VAR

没有返回任何内容。

这是因为环境变量只传递给子进程。没有内置的方法可以设置父 shell 的环境变量。在大多数情况下,这是很好的,可以防止程序影响调用它们的操作环境。

NEW_VAR 变量在我们的子 shell 中被设置为环境变量。这个变量将对其自身和任何其子 shell 和进程可用。当我们退出回到我们的主 shell 时,该环境被销毁。

降级和取消变量

我们仍然将我们的 TEST_VAR 变量定义为环境变量。我们可以通过输入以下命令将其改回为 shell 变量:

export -n TEST_VAR

它不再是环境变量:

printenv | grep TEST_VAR

但它仍然是一个 shell 变量:

set | grep TEST_VAR
TEST_VAR='Hello World!'

如果我们想完全取消一个变量,无论是 shell 还是环境变量,我们可以使用 unset 命令:

unset TEST_VAR

我们可以验证它是否已经取消:

echo $TEST_VAR

没有返回任何内容,因为该变量已被取消。

在登录时设置环境变量

我们已经提到许多程序使用环境变量来决定如何操作的具体细节。我们不想每次启动新的 shell 会话时都要设置重要的变量,而且我们已经看到许多变量在登录时已经设置了,那么我们如何自动创建和定义变量呢?

实际上,这是一个比最初看起来更复杂的问题,因为 bash shell 根据启动方式读取许多配置文件。

登录、非登录、交互和非交互式 shell 会话之间的区别

bash shell 根据会话的启动方式读取不同的配置文件。

不同会话之间的一个区别是 shell 是否作为登录非登录会话生成。

登录 shell 是通过对用户进行身份验证开始的 shell 会话。如果您通过终端会话或 SSH 进行登录并进行身份验证,您的 shell 会话将被设置为登录 shell。

如果您在已经经过身份验证的会话中启动一个新的 shell 会话,就像我们通过终端调用 bash 命令一样,将启动一个非登录 shell 会话。在启动子 shell 时,您没有被要求输入身份验证详细信息。

另一个可以区分的是 shell 会话是否是交互式的,还是非交互式的。

交互式 shell 会话是连接到终端的 shell 会话。非交互式 shell 会话是不连接到终端会话的。

因此,每个 shell 会话都被归类为登录或非登录,交互式或非交互式。

作为登录会话启动的会话将首先从 /etc/profile 文件读取配置详细信息。然后,它将查找用户主目录中的第一个登录 shell 配置文件以获取用户特定的配置详细信息。

它会读取 ~/.bash_profile~/.bash_login 和 ~/.profile 中找到的第一个文件,并且不会再读取任何其他文件。

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

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

实现环境变量

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

这提供了很大的灵活性,可以帮助在特定情况下设置登录 shell 中的某些设置,以及在非登录 shell 中设置其他设置。然而,大多数情况下,我们希望在这两种情况下设置相同的设置。

幸运的是,大多数 Linux 发行版都配置了登录配置文件来源自非登录配置文件。这意味着你可以在非登录配置文件中定义你希望在两种情况下都存在的环境变量。然后这些变量将在两种情况下都被读取。

通常我们会设置特定于用户的环境变量,并且通常希望我们的设置在登录和非登录 shell 中都可用。这意味着定义这些变量的地方是在 ~/.bashrc 文件中。

现在打开这个文件:

nano ~/.bashrc

这很可能已经包含了相当多的数据。这里大多数的定义是用于设置 bash 选项,与环境变量无关。你可以像在命令行中一样设置环境变量:

export VARNAME=value

任何新的环境变量都可以添加到 ~/.bashrc 文件的任何位置,只要它们不被放在另一个命令或 for 循环的中间。然后保存并关闭文件。下次启动 shell 会话时,你的环境变量声明将被读取并传递给 shell 环境。你可以通过输入以下命令强制当前会话立即读取文件:

source ~/.bashrc

如果你需要设置系统范围的变量,你可能需要考虑将它们添加到 /etc/profile、/etc/bash.bashrc 或 /etc/environment 中。

结论

环境变量和 shell 变量始终存在于你的 shell 会话中,非常有用。它们是父进程为其子进程设置配置细节的一种有趣方式,也是在文件之外设置选项的一种方式。

在特定情况下,这有很多优势。例如,一些部署机制依赖环境变量来配置认证信息。这很有用,因为它不需要将这些信息保存在可能被外部人员看到的文件中。

还有许多其他更普通但更常见的情况,你将需要读取或更改系统的环境。这些工具和技术应该为你提供了一个良好的基础,以便进行这些更改并正确使用它们。

以上就是Linux上读取或设置环境和shell变量的教程的详细内容,更多关于Linux设置环境和shell变量的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文