Bash 是如何从环境变量中导入函数的

上文中曾说到:

  • 所谓的环境变量的真实面目其实就是个任意字符串
  • Bash 在启动时会将 environ 数组中包含 = 号的字符串导入成为自己的变量
  • Bash 在启动外部命令时会将自己内部标记为环境变量的变量重组成字符串数组赋值给 environ

本文中继续深入讲三点:

  • environ 数组中可能存在 = 左边名字相同的元素,也就是同名的环境变量,Bash 是怎么导入的?
  • Bash 还可以从环境变量中导入函数,甚至同时导入两个同名的变量和函数
  • Bash 还可以同时导出两个同名的变量和函数

如果有两个同名的环境变量,很简单,那么后面的值会覆盖前面的:


$ env foo=1 foo=2 bash -c ‘echo $foo‘

2

上篇文章中我们没有提到过函数,Bash 其实是可以从环境变量中导入函数的,比如下面这样:


$ foo() { echo foo函数; }

$ export -f foo

$ bash

$ foo

foo函数

上一级的 Shell 把函数传给了它的 child shell,Bash 是怎么实现的呢?我们用 env 命令演示一下:


$ env ‘BASH_FUNC_foo%%=() { echo foo函数; }‘ bash -c ‘foo‘

foo函数

其实 Bash 就是把满足 "BASH_FUNC_函数名%%=(){ 函数体" 格式的环境变量作为函数源码解析并导入。所以两个同名的变量和函数并不会冲突,可以同时导入,像这样:


$ env ‘foo=1‘ ‘BASH_FUNC_foo%%=() { echo $1; }‘ bash -c ‘foo $foo‘

1

既然可以同时导入,那么导出更没问题了:


$ foo=1

$ foo(){ echo foo函数; }

$ export foo;export -f foo

$ env

...

foo=1

BASH_FUNC_foo%%=() { echo foo函数

}

...

Bash 4.3.30 之前的版本

注意,本文所讲的表现仅适用于 Bash 4.3.30 及之后的版本,之前的 Bash 版本在导出函数时不会给函数名加上 BASH_FUNC_ 前缀和 %% 后缀,在导入时也不会识别前缀后缀,只要看到 = 右边是 "() {" 这四个字符,就按函数导入,像这样:


$ env ‘foo=() { echo foo函数; }‘ bash -c ‘foo‘

foo函数

由于环境变量字符串的转换和识别规则不同,假如你在 Bash 4.3.30 中打开一个 Bash 3.2.25,后者是无法继承到前者导出的函数的:


$ bash4.3.30

$ foo() { echo foo函数 ; }

$ export -f foo

$ bash3.2.25

$ foo

bash3.2.25: foo: command not found

反之亦然,同时 foo 会被导入成一个变量:


$ bash3.2.25

$ foo() { echo foo函数 ; }

$ export -f foo

$ bash4.3.30

$ foo

bash3.2.25: foo: command not found

$ echo $foo

() { echo foo函数 }

时间: 2024-10-11 04:52:32

Bash 是如何从环境变量中导入函数的的相关文章

Linux环境变量中PS1

Linux环境变量中PS1是很重要的环境变量: PS(Prompt Sign): 是指命令提示符,例如在Fedora 12的终端下:[[email protected] ~]$ ,在设定PS1环境变量时,我们需要用到预设的一些特殊符号来设定PS1,下面是鸟哥书上关于BASH的特殊变量. o \d :代表日期,格式为 Weekday Month Date,例如 "Mon Aug 1" o \H :完整的主机名称.举例来说,鸟哥的练习机 linux.dmtsai.tw ,那么这个主机名称就

linux CentOS 系统下如何将php和mysql命令加入到环境变量中

在Linux CentOS系统上安装完php和MySQL后,为了使用方便,需要将php和mysql命令加到系统命令中,如果在没有添加到环境变量之前,执行“php -v”命令查看当前php版本信息时时,则会提示命令不存在的错误,下面我们详细介绍一下在linux下将php和mysql加入到环境变量中的方法(假设php和mysql分别安装在/usr/local/webserver/php/和/usr/local/webserver/mysql/中). 方法一:直接运行命令export PATH=$PA

将NuGet配置到环境变量中

https://docs.nuget.org/consume/command-line-reference Installing The NuGet command line may be installed onto a machine in a few possible ways. Direct download of the executable from https://dist.nuget.org/win-x86-commandline/latest/nuget.exe. The ex

getenv和putenv在获取和设置环境变量中的使用

1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <string.h> 4 /* 5 这个函数是对环境变量进行一些操作的 6 */ 7 int main(int argc, char * argv[]) //主函数 8 { 9 char * var, * value; //定义两个字符串指针变量var和value 10 11 if (argc==1||argc>3) //要是没有参数输入和有两个以上的参数输

把当前目录添加到新的环境变量中

@echo off rem 把当前运行的目录添加到系统环境变量里面 rem 环境win7_64 2014/7/29 rem 获得当前目录 set fileName=%0 set fileDir=%fileName:~1,-12% rem 查询注册表中对应的环境变量 for /f "tokens=3*" %%i in ('reg query HKEY_CURRENT_USER\Environment /v path') do @set oldPath=%%i rem 如果环境变量没有定义

由于/usr/bin不在PATH环境变量中,故无法找到该命令

安装Anaconda3时,设置了环境变量: gedit ~/.bashrc 然后在结尾处添加 export PATH=~/anaconda3/bin 之后就出现了终端中gedit等命令不能使用的情况(几乎时所有的命令):由于/usr/bin不在PATH环境变量中,故无法找到该命令 原因:应该时设置环境变量时的问题.不过我没有查找怎样正确设置anaconda3的环境变量,而是直接解决上述提到的问题 1. 先临时设置环境变量 export PATH="$PATH:/usr/bin" 现在这

“LIB 环境变量”中指定的搜索路径 *** 无效 --“系统找不到指定的路径。”

本来我的机器装的是VS2005,后来有一个项目要用VC++6.0开发,没办法装上一个,项目完成后就给卸载了,不想原来的VS2005中C#的项目在Build时报以下警告: 警告    1    “LIB 环境变量”中指定的搜索路径“D:\Program Files\Microsoft Visual Studio\VC98\mfc\lib”无效 --“系统找不到指定的路径. ”    AnalysisCtrl 原来是在安装VC++6.0时,在环境变量里添加了一个叫“lib”的Administrato

环境变量中的用户变量与系统变量的区别

在windows中,设置环境变量的时候,会看到有用户变量跟系统变量2种 那么究竟有什么区别呢? 用户变量:只针对当前用户有效 系统变量:针对整个操作系统有效 为了保证自己的修改不对别人造成影响,那么一般就是用用户变量 对于当前用户而言,设置用户变量跟系统变量大致相同,只是系统变量的路径排在用户变量之前.可能出现一种情况:如果path系统变量中包含java命令,path用户变量中也包含java命令,那么优先执行系统变量中的java命令.

Linux中与环境变量相关的函数

1.在终端可以通过env.set命令查看当前的环境变量 2.通过main函数中的第三个参数可以得到当前进程的环境变量列表 int main(int argc , char *argv[] , char *env[]); 其中argv和env是一个指针数组,数组的最后一个元素为NULL 3.打印当前进程的环境变量 int main(int argc , char *argv[] , char *env[]){ char **p = env; while(*p){ printf("%s\n"