什么是环境变量
bash shell用一个叫作环境变量( environment variable)的特性来存储有关shell会话和工作环
境的信息(这也是它们被称作环境变量的原因)。这项特性允许你在内存中存储数据,以便程序
或shell中运行的脚本能够轻松访问到它们。这也是存储持久数据的一种简便方法。
在bash shell中,环境变量分为两类:
全局变量
局部变量
全局变量
Linux系统在你开始bash会话时就设置了一些全局环境变量。系统环境变量基本上都是使用全大写字母,以区别于普通用户的环境变量。
全局环境变量对于shell会话和所有生成的子shell都是可见的。
局部变量则只对创建它们的shell可见。
使用env或printenv查看环境变量
~]$ printenv XDG_SESSION_ID=148 HOSTNAME=P1HQMSMDW01 MASTER_DATA_DIRECTORY=/gpmaster/gpseg-1 SHELL=/bin/bash TERM=xterm HISTSIZE=1000 GPHOME=/usr/local/greenplum-db-6.15.0 USER=gpadmin PGPORT=5432 LD_LIBRARY_PATH=/usr/local/greenplum-db-6.15.0/lib:/usr/local/greenplum-db-6.15.0/ext/python/lib ...... PGUSER=gpadmin PGDATABASE=qmsprd MAIL=/var/spool/mail/gpadmin PATH=/usr/local/greenplum-cc-6.4.0/bin:/usr/local/greenplum-db-6.15.0/bin:/usr/local/greenplum-db-6.15.0/ext/python/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/usr/local/greenplum-db-clients/bin:/home/gpadmin/.local/bin:/home/gpadmin/bin:/home/gpadmin/postgresql-9.4.24/contrib/pgbench PWD=/home/gpadmin LANG=en_US.UTF-8 PYTHONHOME=/usr/local/greenplum-db-6.15.0/ext/python HISTCONTROL=ignoredups SHLVL=1 HOME=/home/gpadmin PYTHONPATH=/usr/local/greenplum-db-6.15.0/lib/python LOGNAME=gpadmin LESSOPEN=||/usr/bin/lesspipe.sh %s GPCC_HOME=/usr/local/greenplum-cc-6.4.0 _=/bin/printenv
全局环境变量可用于进程的所有子shell
用bash命令生成一个***子shell***后,显示了HOME环境变量的当前值,这个值和父shell中的一模一样,都是/home/gpadmin
~]$ ps -f UID PID PPID C STIME TTY TIME CMD gpadmin 8521 8519 0 16:31 pts/2 00:00:00 -bash gpadmin 14673 8521 0 16:41 pts/2 00:00:00 ps -f ~]$ bash ~]$ ~]$ ps -f UID PID PPID C STIME TTY TIME CMD gpadmin 8521 8519 0 16:31 pts/2 00:00:00 -bash gpadmin 14734 8521 0 16:41 pts/2 00:00:00 bash gpadmin 14841 14734 0 16:42 pts/2 00:00:00 ps -f ~]$ exit exit ~]$ ps -f UID PID PPID C STIME TTY TIME CMD gpadmin 8521 8519 0 16:31 pts/2 00:00:00 -bash gpadmin 15675 8521 0 16:43 pts/2 00:00:00 ps -f
局部变量
局部环境变量只能在***定义它们的进程中可见***。
set命令会显示为某个特定进程设置的所有环境变量,包括局部变量、全局变量
以及用户定义变量。
如果在当前shell中定义了一个变量
~]$ set BASH=/bin/bash BASHOPTS=checkwinsize:cmdhist:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath BASH_ALIASES=() BASH_ARGC=() BASH_ARGV=() BASH_CMDS=() BASH_LINENO=() BASH_SOURCE=() BASH_VERSINFO=([0]="4" [1]="2" [2]="46" [3]="2" [4]="release" [5]="x86_64-redhat-linux-gnu") BASH_VERSION='4.2.46(2)-release' COLUMNS=233 DIRSTACK=() EUID=1000 .......省略 _=444444 colors=/home/gpadmin/.dircolors tmp=444444
可以看到这个变量在set中可以看得到.
当该session退出之后,该变量将消失,是因为其保存在内存中.
env、 printenv和set的区别?
命令env、 printenv和set之间的差异很细微。 set命令会显示出全局变量、局部变量以及用户定义变量。它还会按照字母顺序对结果进行排序。 env和printenv命令同set命令的区别在于前两个命令不会对变量排序,也不会输出局部变量和用户定义变量。在这种情况下, env和printenv的输出是重复的。
设置用户定义变量
设置局部用户定义变量
一旦启动了bash shell(或者执行一个shell脚本),就能创建在这***个shell进程内可见的局部变量***了。可以通过***等号***给环境变量赋值值可以是***数值***或***字符串***。
如果有空格怎么办?
如果要给变量赋一个含有空格的字符串值,必须用单引号来界定字符串的首和尾。
注意:
1、所有的环境变量名均使用大写字母,这是bash shell的标准惯例。
2、如果是你自己创建的局部变量或是shell脚本,请使用小写字母。
3、变量名区分大小写。在涉及用户定义的局部变量时坚持使用小写字母,这能够避免***重新定义系统环境变量可能带来的灾难***。
4、变量名、等号和值之间没有空格,这一点非常重要
如果在赋值表达式中加上了空格,
bash shell就会把值当成一个单独的命令:
这个变量能在新的shell中使用吗?
显然是不可以的.
在这个例子中生成了一个子shell。在子shell中无法使用用户定义变量my_variable。通过命
令echo $my_variable所返回的空行就能够证明这一点。当你退出子shell并回到原来的shell时,这个局部环境变量依然可用。
类似地,如果你在子进程中设置了一个局部变量,那么一旦你退出了子进程,那个局部环境
变量就不可用。
设置全局环境变量
在设定全局环境变量的进程所创建的子进程中,该变量都是可见的。创建全局环境变量的方法是***先创建一个局部环境变量,然后再把它导出到全局环境中***
通过export 关键字来完成将局部变量变成全局变量
bash命令启动了一个子shell。在这个子shell
中能够正确的显示出变量v1的值。该变量能够保留住它的值是因为export命令使其变成了全局环境变量
修改子shell中全局环境变量并不会影响到父shell中该变量的值
在定义并导出变量v1后, bash命令启动了一个子shell。在这个子shell中能够正确显示出全局环境变量v1的值。子shell随后改变了这个变量的值。
这种改变仅在子shell中有效,并不会被反映到父shell中。
子shell无法使用export命令改变父shell中全局环境变量的值
删除环境变量
用***unset***命令完成这个操作。在unset命令中引用环境变量时,记住不要使用$。
问题: 什么时候该使用美元符,什么时候不该使用?
1、如果要用到变量,使用 $;
2、如果要操作变量,不使用$。
这条规则的一个例外就是使用printenv显示某个变量的值
环境变量是严格区分大小写的.
子进程中删除了一个全局环境变量,只对子进程有效
默认的 shell 环境变量
默认情况下, bash shell会用一些特定的环境变量来定义系统环境。这些变量在你的Linux系统上都已经设置好了,只管放心使用。 bash shell源自当初的Unix Bourne shell,因此也保留了Unix
Bourne shell里定义的那些环境变量。
最常用的的标注出来
除了默认的Bourne的环境变量, bash shell还提供一些自有的变量
1、BASH 当前shell实例的全路径名
2、BASHPID 当前bash进程的PID
3、COLUMNS 当前bash shell实例所用终端的宽度BASH_SUBSHELL 当前子shell环境的嵌套级别(初始值是0)
4、BASH_VERSINFO 含有当前运行的bash shell的主版本号和次版本号的数组变量
5、BASH_VERSION 当前运行的bash shell的版本号
HISTFILE 保存shell历史记录列表的文件名(默认是.bash_history)
HISTFILESIZE 最多在历史文件中存多少行
设置 PATH 环境变量
当你在shell命令行界面中输入一个外部命令时, shell必须搜索系统来找到对应
的程序。 PATH环境变量定义了用于进行命令和程序查找的目录
当安装了一个新的程序,如何将其也加入环境变量中来避免每次都要输入一个绝对路径.
使用echo $PATH 可以查看当前的shell用来查找命令和程序。 PATH中的目录使用冒号分隔。
~]$ echo $PATH /usr/local/greenplum-cc-6.4.0/bin:/usr/local/greenplum-db-6.15.0/bin:/usr/local/greenplum-db-6.15.0/ext/python/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/usr/local/greenplum-db-clients/bin:/home/gpadmin/.local/bin:/home/gpadmin/bin:/home/gpadmin/postgresql-9.4.24/contrib/pgbench
最后一个pgbenc就是后来才加入的一个时PATH
这样就可以在任当前添加bash_profile的用户下任何目录使用该命令了.
需要注意:
对PATH变量的修改只能持续到退出或重启系统。这种效果并不能一直持续。
如何永久生效呢?
定位系统环境变量
在你登入Linux系统启动一个bash shell时,默认情况下bash会在几个文件中查找命令。这些
文件叫作启动文件或环境文件。 bash检查的启动文件取决于你启动bash shell的方式。启动bash
shell有3种方式
定位系统
- 环境变量
- 作为非登录shell的交互式shell
- 作为运行脚本的非交互shell
登录 shell
当你登录Linux系统时, bash shell会作为登录shell启动。登录shell会从5个不同的启动文件里
读取命令:
/etc/profile
$HOME/.bash_profile
$HOME/.bashrc
$HOME/.bash_login
$HOME/.profile
/etc/profile文件是系统上默认的bash shell的主启动文件。系统上的每个用户登录时都会执行这个启动文件
另外4个启动文件是针对用户的,可根据个人需求定制
1./etc/profile文件
/etc/profile文件是bash shell默认的的主启动文件。只要你登录了Linux系统, bash就会执行
/etc/profile启动文件中的命令。不同的Linux发行版在这个文件里放了不同的命令
~]# cat /etc/profile # /etc/profile # System wide environment and startup programs, for login setup # Functions and aliases go in /etc/bashrc # It's NOT a good idea to change this file unless you know what you # are doing. It's much better to create a custom.sh shell script in # /etc/profile.d/ to make custom changes to your environment, as this # will prevent the need for merging in future updates. pathmunge () { case ":${PATH}:" in *:"$1":*) ;; *) if [ "$2" = "after" ] ; then PATH=$PATH:$1 else PATH=$1:$PATH fi esac } if [ -x /usr/bin/id ]; then if [ -z "$EUID" ]; then # ksh workaround EUID=`/usr/bin/id -u` UID=`/usr/bin/id -ru` fi USER="`/usr/bin/id -un`" LOGNAME=$USER MAIL="/var/spool/mail/$USER" fi # Path manipulation if [ "$EUID" = "0" ]; then pathmunge /usr/sbin pathmunge /usr/local/sbin else pathmunge /usr/local/sbin after pathmunge /usr/sbin after fi HOSTNAME=`/usr/bin/hostname 2>/dev/null` HISTSIZE=1000 if [ "$HISTCONTROL" = "ignorespace" ] ; then export HISTCONTROL=ignoreboth else export HISTCONTROL=ignoredups fi export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL # By default, we want umask to get set. This sets it for login shell # Current threshold for system reserved uid/gids is 200 # You could check uidgid reservation validity in # /usr/share/doc/setup-*/uidgid file if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then umask 002 else umask 022 fi for i in /etc/profile.d/*.sh /etc/profile.d/sh.local ; do if [ -r "$i" ]; then if [ "${-#*i}" != "$-" ]; then . "$i" else . "$i" >/dev/null fi fi done unset i unset -f pathmunge
for语句。它用来迭代/etc/profile.d目录下的所有文件。
这为Linux系统提供了一个放置特定应用程序启动文件的地方,当用户登录时, shell会执行这些文件。
大部分应用都会创建两个启动文件:
一个供bash shell使用(使用.sh扩展名)
一个供c shell使用(使用.csh扩展名)。
lang.csh和lang.sh文件会尝试去判定系统上所采用的默认语言字符集,然后设置对应的LANG
环境变量
2. $HOME目录下的启动文件
剩下的启动文件都起着同一个作用:提供一个用户专属的启动文件来定义该用户所用到的环
境变量。大多数Linux发行版只用这四个启动文件中的一到两个:
$HOME/.bash_profile
$HOME/.bashrc
$HOME/.bash_login
$HOME/.profile
所以每个用户都可以编辑这些文件并添加自己的环境变
量,这些环境变量会在每次启动bash shell会话时生效。
shell会按照按照下列顺序,运行第一个被找到的文件,余下的则被忽略:
$HOME/.bash_profile
$HOME/.bash_login
H O M E / . p r o f i l e 注 意 , 这 个 列 表 中 并 没 有 HOME/.profile 注意,这个列表中并没有HOME/.profile注意,这个列表中并没有HOME/.bashrc文件。这是因为该文件通常通过其他文件运行的。
Centos .bahs_profile的内容
~]$ more .bash_profile # .bash_profile # Get the aliases and functions if [ -f ~/.bashrc ]; then . ~/.bashrc fi # User specific environment and startup programs PGBENCH_HOME=/home/gpadmin/postgresql-9.4.24/contrib/pgbench PATH=$PATH:$HOME/.local/bin:$HOME/bin:$PGBENCH_HOME export PATH
.bash_profile启动文件会先去检查HOME目录中是不是还有一个叫**.bashrc的启动文件**。 如果有的话,会先执行启动文件里面的命令。 这也就是说 可以把pgbench这个变量放在bashrc中.
交互式shell
如果你的bash shell不是登录系统时启动的(比如是在命令行提示符下敲入bash时启动),那
么你启动的shell叫作交互式shell。交互式shell不会像登录shell一样运行,但它依然提供了命令行提示符来输入命令。
如果bash是作为交互式shell启动的,它就不会访问/etc/profile文件,只会检查用户HOME目录中的.bashrc文件。
.bashrc文件有两个作用
1、查看/etc目录下通用的bashrc文件
2、为用户提供一个定制自己的命令别名和私有脚本函数的地方
非交互式shell
系统执行shell脚本时用的就是这种shell。不同的地方在于它没有命令行提示符(这也是平常用的最多的一种脚本执行方式,例如crontab)
但是当你在系统上运行脚本时,也许希望能够运行一些特定启动的命令。
为了处理这种情况, bash shell提供了BASH_ENV环境变量。当shell启动一个非交互式shell进
程时,它会检查这个环境变量来查看要执行的启动文件。如果有指定的文件, shell会执行该文件里的命令,这通常包括shell脚本变量设置。
那如果BASH_ENV变量没有设置, shell脚本到哪里去获得它们的环境变量呢?别忘了有些
shell脚本是通过启动一个子shell来执行的。
子shell可以继承父shell导出过的变量。
举例来说,如果父shell是登录shell,在/etc/profile、 /etc/profile.d/*.sh和$HOME/.bashrc文件中设置并导出了变量,用于执行脚本的子shell就能够继承这些变量。
记住,由父shell设置但并未导出的变量都是局部变量。子shell无法继承局部变量。
也就是说如果在远程执行一个嵌套了脚本的脚本中定义了一个变量,该变量为局部变量,因此无法在被嵌套的shell中执行.
实例说明:
…
对于那些不启动子shell的脚本,变量已经存在于当前shell中了。
所以就算没有设置BASH_ENV,也可以使用当前shell的局部变量和全局变量。
环境变量持久化
全局环境变量来说( Linux系统中所有用户都需要使用的变量),可能更倾向于将新的或修
改过的变量设置放在/etc/profile文件中,但这可不是什么好主意。如果你升级了所用的发行版,
这个文件也会跟着更新,那你所有定制过的变量设置可就都没有了。
最好是在/etc/profile.d目录中创建一个以.sh结尾的文件。把所有新的或修改过的全局环境变
量设置放在这个文件中。
在大多数发行版中,存储个人用户永久性bash shell变量的地方是$HOME/.bashrc文件。
什么是外部命令?什么是内建命令?
1、外部命令,有时候也被称为文件系统命令,是存在于bash shell之外的程序。它们并不是shell
程序的一部分。外部命令程序通常位于/bin、 /usr/bin、 /sbin或/usr/sbin中。这部分就是后来安装在系统上的软件一样.例如 mysql、nginx、keepalived…
ps就是一个外部命令。你可以使用which和type命令找到它
2、内建命令和外部命令的区别在于前者不需要使用子进程来执行。它们已经和shell编译成了一体,作为shell工具的组成部分存在。不需要借助外部程序文件来运行
which命令只显示出了外部命令文件