定义带有或不带导出的Bash变量
1. 简介
当我们阅读不同的 Linux bash 命令和脚本时,我们经常遇到定义 shell 变量的两种不同方法:使用和不使用export命令。在定义 bash 变量时简单添加export命令会更改该变量的整个范围。
在本教程中,我们将讨论使用和不使用export定义 bash 变量之间的区别。
我们还将探讨export命令、其选项和相关命令的不同用法。
2. 有export与无export
Bash 变量非常方便,就像其他编程语言中的变量一样,例如 Java 或 C++。一个主要区别是它们不需要声明。只需为变量名赋值即可创建一个变量:
$ MYVAR=1729
$ export MYVAR=1729
第一个定义创建了一个名为MYVAR的变量并将其赋值为1729。这是一个shell 变量。
使用export命令的第二个定义是定义变量的另一种方式。它创建一个名为MYVAR的变量,为其分配值1729,并将其标记为导出到从该 shell 创建的所有子进程。这是一个环境变量。
这两者之间的主要区别在于export命令使该变量可用于该 shell 中执行的所有后续命令。此命令通过设置 shell 变量MYVAR的导出属性来实现。** export属性将 MYVAR 标记为自动导出到由后续命令创建的子进程的环境**:
$ export MYVAR=1729
$ echo $MYVAR
1729
$ bash # Open a new child shell
$ echo $MYVAR
1729
让我们将其与未定义export的 shell 变量进行对比,后者仅在该 shell 中可用。任何子 shell、进程或后续命令都无法访问它:
$ MYVAR=1729
$ echo $MYVAR
1729
$ bash # Open a new child shell
$ echo $MYVAR
$
如果我们将 bash 变量与编程语言中的变量进行比较:
- Shell 变量(未定义export)就像我们只能在该 shell 中访问的局部变量。
- 环境变量(用export定义)就像我们可以在定义的 shell 及其所有子 shell、进程和命令中访问的全局变量。
但是,如果我们将 bash 环境变量与编程语言的全局变量进行比较,则有一个主要区别。我们只能通过一种方式访问 bash 环境变量;父 shell 将其变量导出到子 shell 的环境,但子 shell 不能将变量导出回父 shell。
3. 用法:export或不带export
我们刚刚了解了带和不带export的变量定义之间的区别。但是什么时候应该使用export什么时候不应该使用export呢?
当我们想要导出变量并使它们可用于后续命令或进程时,我们使用环境变量(带有export )。通常我们使用它来与子进程共享环境:
当我们希望变量仅在父 shell 中可用并且不想污染子进程的环境时,我们使用 shell 变量(不带export ):
- 循环计数器变量
- 临时变量
4. export命令
现在让我们深入了解export和其他在处理环境变量和 shell 变量时经常使用的相关命令的更多细节。
4.1.导出 Bash 函数
除了 bash 变量之外,export 命令还可以导出 bash函数。
我们可以使用export -f命令行选项来导出函数,以便它们在子 shell 和进程中也可用:
$ func(){
> echo hi
> }
$ func
hi
$ bash # Open a new child shell
$ func
bash: func: command not found
$ exit # Back to parent shell
$ export -f func
$ bash # Open a new child shell
$ func
hi
4.2. 从export中删除变量
使用export定义的环境变量会自动导出到所有子 shell,以及它们的子 shell,依此类推。但是如果我们已经在子 shell 中,我们就会从父 shell 继承一些环境变量。如果我们不想自动将这些变量导出到我们的子 shell,export提供了一个命令行选项*-n来从export*中删除一个变量:
$ echo $USER
ubuntu
$ bash # Open a new child shell
$ echo $USER
ubuntu
$ exit # Back to parent shell
$ export-n USER
$ bash # Open a new child shell again
$ echo $USER
$
4.3. 列出所有导出的变量
不带选项或带*-p选项的export*命令显示在当前 shell 中导出的所有变量和函数的列表:
$ export -p
declare -x COLORTERM="truecolor"
declare -x DESKTOP_SESSION="ubuntu"
declare -x DISPLAY=":0"
declare -x GDMSESSION="ubuntu"
declare -x LESSCHARSET="latin1"
declare -x LESSCLOSE="/usr/bin/lesspipe %s %s"
declare -x LESSOPEN="|/usr/bin/lesspipe.sh %s 2>&-"
.
.
declare -x XDG_SESSION_DESKTOP="ubuntu"
declare -x XDG_SESSION_ID="2"
declare -x XDG_SESSION_TYPE="x11"
declare -x XDG_VTNR="1"
这对于验证我们是否正确导出了我们为导出定义的变量非常有用。
4.4. 自动导出所有定义的变量
有时自动导出我们在当前 shell 中定义的所有变量很有用。bash shell 选项allexport帮助我们做到这一点。
我们可以使用set 命令启用或禁用它,就像任何其他 bash shell 选项一样:
$ set -a # Enable allexport using single letter syntax
$ set -o allexport # Enable using full option name syntax
$ set +a # Disable allexport using single letter syntax
$ set +o allexport # Enable using full option name syntax
$ set -a
$ MYVAR=1729 # no export
$ bash # Open a new child shell
$ echo $MYVAR
1729
我们经常在调用 bash 脚本之前启用此 shell 选项,该脚本定义了许多没有export命令的变量。
5. 父shell和子shell的关系
在处理环境变量时,我们需要注意一些关于父shell、子shell、子shell的子等shell层次结构的点:
父shell | 子shell |
---|---|
父 shell 将其变量导出到子 shell 的环境中。 | 子 shell 不能将变量导出或修改回父 shell。 |
子 shell 导出的变量在父 shell 中不可用。 | 此后,由子 shell 导出的变量仅在子 shell 的子代中可用,依此类推。 |
父 shell 在创建子 shell 时复制导出的变量及其值。 | 子 shell 维护这些环境变量的副本。 |
6. Bash 脚本和export
当我们创建包含export命令的 bash 脚本并从 bash shell 调用它们时,我们需要确保使用export命令获得预期的结果。
6.1. 运行 Bash 脚本时export
当我们直接从 shell 或使用 bash 命令执行包含导出命令的 bash 脚本时,这些脚本在它们自己的子 shell 中运行。这意味着脚本导出的任何变量都只能用于其子 shell 而不能用于父 shell。因此,当脚本完成执行时,导出的变量将从环境中消失:
$ echo "export MYVAR=1729" > myscript.sh
$ chmod +x myscript.sh
$ ./myscript.sh
$ echo $MYVAR
$
6.2. 从 Bash 脚本到当前 Shell 的source
正如我们刚刚看到的,bash 脚本不会将其导出的变量导出回调用 shell。为了处理这种特殊情况,bash 提供了source 命令。source命令或点 (.)命令在当前 shell 上下文中执行 bash 脚本,而不创建子 shell。因此,我们不需要源脚本中的导出命令。source命令对于将变量和函数加载到 bash shell 中很有用:
$ echo "MYVAR=1729" > myscript.sh
$ source myscript.sh
$ echo $MYVAR
1729