Answers:
环境并不像看起来那样神奇。Shell将其存储在内存中并传递给execve()
系统调用。子进程将其作为称为的数组指针继承environ
。从execve
联机帮助页:
概要
#include <unistd.h> int execve(const char *filename, char *const argv[], char *const envp[]);
argv
是传递给新程序的参数字符串数组。
按照约定,这些字符串中的第一个应包含与正在执行的文件关联的文件名。envp
是一个字符串数组,通常为key = value形式,将作为环境传递给新程序。
该手册environ(7)
页还提供了一些见解:
概要
extern char **environ;
描述
该变量
environ
指向一个称为“环境”的字符串指针数组。此数组中的最后一个指针的值为NULL
。(必须在用户程序中声明此变量,但<unistd.h>
如果头文件来自libc4或libc5,并且如果它们来自glibc并定义了_GNU_SOURCE ,则在头文件中声明。)此字符串数组可用于通过启动该过程的exec(3)调用来处理该过程。
这两个GNU手册页都符合POSIX规范
exec*e
是显式传递env的environ
变量,而不是隐式使用全局变量。的v
手段“载体”,并且指的是作为一个阵列(而不是“列表”(可变长度函数))通过命令行参数 execve
是一个系统调用,和所有其他的exec*
功能是它的libc包装。
您有一点点错误:SOME_NAME=value
创建一个shell变量(在大多数shell中)。export SOME_NAME=value
创建一个环境变量。不管好坏,大多数Unix / Linux / * BSD Shell在访问环境变量和Shell变量时使用相同的语法。
从更大的意义上讲,“环境”只是程序执行所伴随的信息。在C程序中,您可能会找到带有getpid()
调用的进程ID ,在Shell程序中,您将使用变量访问:$$
。进程ID只是程序环境的一部分。我相信“环境”一词来自一些更理论上的计算机科学主题,例如对程序执行进行建模。程序执行模型具有一种“包含变量及其值之间的关联” 的环境。
对于后者,更严格的定义是Unix / Linux / * BSD shell的“环境”:名称(“变量”)及其值之间的关联。对于大多数Unix风格的shell,值都是字符串,尽管这并不像过去那样严格。这些天,Ksh,Zsh和Bash都输入了类型变量。甚至可以导出外壳函数定义。
使用与普通外壳变量分开的环境涉及fork/exec
启动所有Unix使用的新进程的方法。当您使用export
一个名称/值对时,该名称/值对将出现在新的可执行文件的环境中,由外壳程序通过execve(2)
系统调用(通常在后面跟随fork(2)
,exec
使用shell命令时除外)启动。
在之后execve()
,main()
新二进制文件的功能具有其命令行参数,环境(存储为指向var=value
字符串的NULL终止数组,请参见environ(7)
手册页)。继承的其他状态包括ulimit
设置,当前工作目录以及execve()
调用者未为其设置FD_CLOEXEC的任何打开的文件描述符。tty的当前状态(启用回显,原始模式等)也可以视为新exec
进程继承的执行状态的一部分。
有关简单命令(内置或外壳函数除外),请参见bash
手册对执行环境的描述。
Unix环境至少与某些其他操作系统不同:VMS“词汇”可以由子进程更改,并且该更改在父进程中可见。cd
子进程中的VMS 将影响父进程的工作目录。至少在某些情况下,我的记忆可能使我失望。
一些环境变量是众所周知的,$HOME
,$PATH
,$LD_LIBRARY_PATH
等。对于给定的编程系统,有些是常规的,因此父shell可以将很多特殊用途的信息传递给某个程序,例如特定的临时目录或未显示在中的用户ID和密码ps -ef
。例如,简单的CGI程序会通过环境变量从Web服务器继承很多信息。
SOME_NAME=value command
将为该命令调用设置SOME_NAME环境变量。令人困惑的是,似乎没有设置相同名称的shell变量。
SOME_NAME=value command
行为与预期相反的原因是它是一种特殊的语法,意思是“将SOME_NAME添加到传递给命令的环境中,但不要更改此Shell的变量”。
fork()
编辑,但是它们确实接收(复制)外壳程序变量。
最原始形式的环境变量只是一组名称/值对。如bash手册页(man 1 bash
)中“环境”部分所述:
When a program is invoked it is given an array of strings called the
environment. This is a list of name-value pairs, of the form
name=value.
The shell provides several ways to manipulate the environment. On
invocation, the shell scans its own environment and creates a parameter
for each name found, automatically marking it for export to child pro-
cesses. Executed commands inherit the environment.
实际上,它允许您定义与从当前Shell调用的程序共享或唯一的行为。例如,当使用crontab
或时,visudo
您可以定义EDITOR
环境变量来定义另一个编辑器,而不是系统默认使用的编辑器。对于诸如man
查看您的PAGER
环境以找出应该使用哪个页面程序来显示手册页输出的命令之类的事情,也是如此。
大量的Unix命令读取环境,并根据设置的内容,根据这些内容更改其输出/处理/操作。有些是共享的,有些是该程序独有的。大多数手册页包含有关环境变量如何影响所描述程序的信息。
其他实用示例适用于诸如在同一平台上多次安装Oracle的系统之类的事情。通过设置ORACLE_HOME
,整套oracle命令(从PATH
环境变量中加载)然后从该顶级目录下获取设置,定义,映射和库。具有JAVA_HOME
环境变量的其他程序(例如java)也是如此。
bash本身具有许多环境变量,这些变量可以更改历史记录(HISTSIZE
,HISTFILE
等),屏幕大小(COLUMNS
),制表符完成(FIGNORE
,GLOBIGNORE
)语言环境和字符编码/解码(LANG
,LC_*
),提示(PS1
.. PS4
)和等等(再次从bash手册页中寻求知识)。
您还可以编写使用自己的自定义环境变量(以传递设置或更改功能)的脚本/程序。
“环境变量”是一组动态的命名值,可以影响正在运行的进程在计算机上的行为方式。
它们是运行流程的操作环境的一部分。例如,正在运行的进程可以查询TEMP环境变量的值以发现合适的位置来存储临时文件,或者可以查询HOME或USERPROFILE变量来查找运行该进程的用户所拥有的目录结构。
此处了解更多信息→ http://en.wikipedia.org/wiki/Environment_variable。
您想了解的有关环境变量的所有信息...↑
这个答案需要一些shell脚本经验和知识,包括变量,值,变量替换,提示,回显,内核,shell,实用程序,会话和进程。
一个环境变量(ENVAR)是一组全局定义的变量可以影响一个给定的进程将表现在计算机的操作系统的方式。
我们用en $
和大写字母代替envar 。例如:$PS1
。
我们可以这样打印envar:
echo $PS1
$PS1
保存Unix提示符的值。说它的本机价值是\u
\w
$
。
\u
代表(当前)用户,\w
代表工作目录,$
是边框提示。所以,如果我们这样做:echo $PS1
,我们看到的价值\u
,\w
再加上年底的美元符号。
如果我们更改该envar的值,则可以在这种情况下更改Unix行为。例如:
PS1="\w >"
现在,提示如下所示(假设工作目录名为“ John”):
John >
我们可以采用相同的方式进行操作PS1="Hello, I'm your prompt >"
,因此echo $PS1
会带来:
Hello, I'm your prompt >
在Bash 4.xx中,我们可以使用以下env
命令在系统中打印所有envar 。我建议env
在终端中执行并看一下输出。
会话的终端让我们自定义Bash随附的envar。
前面提到的更改通常是暂时的,原因如下:
每个会话(不是子会话)都是唯一的,并且多个进程可以同时唯一地运行(每个进程都有自己的一组envar),但通常从会话0到会话1以及更高版本都有继承。
我们对一个流程所做的更改是该流程所独有的,如果我们在不以某种方式保存它们的情况下将其关闭,则更改将停止。
根据我们选择的范围,可以使用几种类型的方法来存储envar更改。以下是此类更改的不同范围(级别):
Unix由3个主要层构成:内核,shell和实用程序。AFAIK每个shell都有其自己的envar,它们主要或专门在shell中构建。
/etc/profile
尽管我们.bashrc
当然也可以这样做,但是通常可以在哪些特定位置进行全局更改。
我们可以创建新的envar,这是一种方法。从Bash 4.xx版本开始,没有命名MESSAGE
为本地的enavar (如上所述,envar通常是大写的)。
MESSAGE="Hello world!"
将为我们创建它,现在,如果我们键入echo $MESSAGE
,我们将得到hello world!
。
如果我们要bash
在当前的工作会话(窗口)中执行,则将启动一个新的bash子会话,除非我们执行,否则它将不再在原始进程中工作exit
。
注意:在带有终端仿真器的操作系统(例如Ubuntu桌面)中,子会话通常在同一窗口上运行,但是在另一个窗口中的新会话不是现有窗口的子会话(它是相邻进程)。 。
注意:不要在envar值中使用特殊符号,例如!。否则将无法保存。
我们仍然可以使用在第一个会话中创建的envar,以及在第二个会话中创建的envar,而无需将其注册到用户或全局级别的conf文件中(请参阅以下数据)。这样做的方法如下:
转到原始会话(无论是在当前窗口还是其他窗口)并执行:
export MESSAGE
导出时,请勿使用$
标志。
现在将其导出到所有子会话。如果您要进行echo $MESSAGE
子会话,无论是来自您的用户还是来自另一个用户,都将随后打印该会话。
请注意,PS1
不应导出诸如之类的Shell内部变量,但是如果您确实想出于任何原因将其导出并且它们没有出现,则不要在bash
之后执行export
,而是执行bash –norc
。
$PATH
用户通常最容易改变的嫉妒。
如果是echo $PATH
,我们将看到以下流:
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
此envar的打印值在那里用冒号(:)分隔,但这是一种可能更舒适的方式(这些值相同):
/usr/local/bin
/usr/bin
/bin
/usr/local/games
/usr/games
这些是我们运行实用程序时要搜索的目录。
通过执行,which echo
我们将获得它的文件位置-例如,我们可能会看到它存在于中/bin/echo
。
基于此,我们不必键入echo envar即可查看evnar的值。我们还可以:
/bin/echo $ENVAR
该envar仍将执行,例如:
/bin/echo $HOME
给我们
/home/User || /root
就像:
echo $HOME
给我们
/home/User || /root
注意:$HOME
缩写为~
。
在Bash 4.xx中,当我们使用没有完整路径的实用程序时,系统将使用上述$PATH
envar的所有6个值。因此,它将从开始/user/local/bin
,并将跟随其所有内容以寻找echo
可执行文件。
在这种情况下,它将在处停止/bin/echo
,在这种情况下,可执行文件将驻留在该位置。
因此,我们可能自定义$PATH
envar的主要原因是安装不在其任何本机值下的可执行文件。
在安装了此类可执行文件之后,我们应该相应地设置它们的$PATH
值,然后就可以使用它们了。
$PATH
:我们可以export $PATH
通过以下方式对子会话进行bash(包括bash扩展,如用于WordPress的WP-CLI或用于Drupal的Drush):
export PATH="/home/John:$PATH"
这将添加一个新的价值/home/John
来$PATH
,然后用鼠标右键后,将吞并任何原生值了,其中存储了语法下(冒号后右)$PATH
。
此类永久更改可以在相关脚本中完成,通常/etc/profile
使用名称进行更改.bashrc
。
!
环境变量值不起作用,正好在显示该变量有效的示例下面,错误的子会话概念,关于该做什么的非常奇怪的建议导出shell变量和全局环境变量的错误概念之后。
warning about ! in an environment variable value not working that is right below an example showing it working
?请举个例子。
quite bizarre advice about what to do after exporting a shell variable
, 你到底什么意思?
false notion of global environment variables
, 你到底什么意思?
exec(3)
家庭的某些成员(即与exec * v不匹配的那些成员)在掩体下通过了**环境。