介绍
当通过shell会话与服务器交互时,shell编译了许多信息,以确定其行为和资源访问。 这些设置中的一些包含在配置设置内,而其他设置由用户输入确定。
该壳跟踪所有的这些设置和细节的一种方法是通过它保持称为环境的区域。 环境是shell每次启动包含定义系统属性的变量的会话时构建的区域。
在本指南中,我们将讨论如何与环境交互并通过配置文件交互式地读取或设置环境和shell变量。 我们将使用Ubuntu 12.04 VPS作为示例,但这些详细信息应该在任何Linux系统上相关。
环境和环境变量如何工作
每当shell会话产生时,都会执行一个进程来收集和编译应该对shell进程及其子进程可用的信息。 它从系统上的各种不同文件和设置获取这些设置的数据。
基本上,环境提供了一个媒介,通过它,shell进程可以获取或设置设置,并将这些传递给它的子进程。
环境实现为表示键值对的字符串。 如果传递多个值,它们通常用冒号(:)字符分隔。 每对将通常看起来像这样:
KEY=value1:value2:...
如果值包含显着的空格,则使用引号:
KEY="value with spaces"
这些场景中的键是变量。 它们可以是两种类型之一,环境变量或shell变量。
环境变量是为当前shell定义和任何子外壳或进程继承的变量。 环境变量用于将信息传递到从shell生成的进程中。
壳变量是在它们被设置或限定在外壳内只包含变量。 它们通常用于跟踪临时数据,如当前工作目录。
按照惯例,这些类型的变量通常使用所有大写字母定义。 这有助于用户在其他上下文中区分环境变量。
打印外壳和环境变量
每个shell会话都跟踪自己的shell和环境变量。 我们可以以几种不同的方式访问这些。
我们可以通过看我们所有的环境变量的列表, env
或printenv
命令。 在默认状态下,它们应该完全相同:
printenv
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 SHELL
/bin/bash
在另一方面, env
使你可以修改环境,程序运行中通过传递一组变量定义成这样的命令:
env VAR1="blahblah" 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中执行它,这样它不会改变我们当前的环境:
(set -o posix; set)
这将列出所有定义的环境和shell变量。
我们可以尝试此输出与输出比较env
或printenv
命令,来尝试只得到shell变量的列表,但是这将是不完美的,由于不同的方式,这些命令的输出信息:
comm -23 <(set -o posix; set | sort) <(env | sort)
这将有可能仍然包含一些环境变量,由于这样的事实,该set
命令输出引用的值,而printenv
和env
命令不引用字符串的值。
这应该还是给你一个好主意的环境和shell变量在会话中设置。
这些变量用于各种各样的事情。 它们提供了一种为进程之间的会话设置持久值的替代方法,而无需对文件进行任何更改。
常见的环境和Shell变量
一些环境和shell变量是非常有用的,并被相当频繁地引用。
这里有一些常见的环境变量,你会遇到:
SHELL:这说明将解释你输入任何命令外壳在大多数情况下,这将是默认bash的,但如果你喜欢其他选项其他值可以设置。
期限 :本指定终端上运行的shell时仿效的类型。 可以为不同的操作要求模拟不同的硬件端子。 你通常不需要担心这个,虽然。
USER:当前登录的用户。
PWD:当前的工作目录。
OLDPWD:前一个工作目录。 这是由外壳,以便通过运行切换回以前的目录存放
cd -
LS_COLORS:定义了用于可选的彩色输出添加到颜色代码
ls
命令。 这是用来区分不同的文件类型,并提供更多的信息给用户一目了然。MAIL:以当前用户的邮箱的路径。
PATH:目录的查找命令时,系统会检查列表。 当用户键入命令时,系统将按此顺序检查可执行文件的目录。
郎咸平 :目前的语言和本地化设置,包括字符编码。
HOME:当前用户的主目录。
_:最近以前执行的命令。
除了这些环境变量,你会经常看到的一些shell变量:
BASHOPTS:被执行庆典时所使用的选项列表。 这可以有助于找出shell环境是否以您想要的方式运行。
BASH_VERSION:庆典的版本被执行,在人类可读的形式。
BASH_VERSINFO:庆典的版本,以机器可读的输出。
柱 :正在使用在屏幕上绘制输出宽的列数。
DIRSTACK:可用与目录的堆
pushd
和popd
命令。HISTFILESIZE:保存到一个文件中的命令历史记录的行数。
HISTSIZE:允许在内存命令历史记录的行数。
主机名 :计算机的此时的主机名。
IFS:内部字段分隔符在命令行中输入分开。 默认情况下,这是一个空格。
PS1:初级命令提示符下定义。 这用于定义在启动shell会话时您的提示符。 在
PS2
用于声明为当一个命令跨越多行二次提示。SHELLOPTS:可与设定Shell选项
set
选项。UID:当前用户的UID。
设置Shell和环境变量
为了更好地理解shell和环境变量之间的区别,并引入设置这些变量的语法,我们将做一个小的演示。
创建Shell变量
我们将首先在当前会话中定义一个shell变量。 这很容易实现; 我们只需要指定一个名称和一个值。 我们将遵循保持变量名的所有大写的约定,并将其设置为一个简单的字符串。
TEST_VAR='Hello World!'
在这里,我们使用引用,因为我们的变量的值包含一个空格。 此外,我们使用单引号,因为感叹号是bash shell中的一个特殊字符,如果未转义或放入单引号,通常会扩展到bash历史。
我们现在有一个shell变量。 此变量在当前会话中可用,但不会传递到子进程。
我们可以通过grepping为我们在新的变量看到这set
输出:
set | grep TEST_VAR
TEST_VAR='Hello World!'
我们可以验证这是不是想用同样的环境变量printenv
:
printenv | grep TEST_VAR
不应退回。
让我们把这作为一个机会来演示访问任何shell或环境变量的值的方法。
echo $TEST_VAR
Hello World!
正如你所看到的,通过与它前面引用变量的值$
符号。 shell接受这意味着当它遇到这个变量时,它应该替换变量的值。
所以现在我们有一个shell变量。 它不应该传递给任何子进程。 我们可以从我们当前的演示中生成一个新的bash shell:
bash
echo $TEST_VAR
如果我们输入bash
来派生子shell,然后尝试访问该变量的内容,什么也不会退回。 这是我们的期望。
通过键入我们回到原来的壳exit
:
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,那个环境被毁了。
降级和取消设置变量
我们仍然有我们的TEST_VAR
变量定义为环境变量。 我们可以通过键入以下内容将其改回为shell变量:
export -n TEST_VAR
它不再是一个环境变量:
printenv | grep TEST_VAR
但是,它仍然是一个shell变量:
set | grep TEST_VAR
TEST_VAR='Hello World!'
如果我们想彻底取消设置变量,无论是外壳还是环境,我们可以用这样做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会话被分类为登录或非登录以及交互或非交互。
以SSH开头的正常会话通常是交互式登录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
然后我们可以保存并关闭文件。 下一次启动shell会话时,您的环境变量声明将被读取并传递到shell环境。 您可以通过键入以下命令强制当前会话读取该文件:
source ~/.bashrc
如果您需要设置系统范围的变量,你可能要考虑将其添加到/etc/profile
, /etc/bash.bashrc
,或/etc/environment
。
结论
环境和shell变量总是存在于shell会话中,可能非常有用。 它们是父进程为其子进程设置配置详细信息的有趣方法,也是一种在文件外设置选项的方法。
这在特定情况下具有许多优点。 例如,一些部署机制依赖环境变量来配置认证信息。 这是有用的,因为它不需要将这些保存在外部各方可能看到的文件中。
有很多其他的,更平凡的,但更常见的情况下,你将需要读取或改变您的系统的环境。 这些工具和技术应为您提供进行这些更改和正确使用这些更改的良好基础。