(6)Linux学习之环境变量

6.使用Linux环境变量

学习内容在《Linux命令行与shell脚本编程大全(第3版)》一书当中,欢迎大家一起来学习!

前言

环境变量有啥作用?

Linux环境变量可以帮助我们提升Linux shell的体验。

因为很多程序和脚本都通过环境变量来获取系统信息、存储临时数据和配置信息

在Linux系统当中有很多地方都可以设置环境变量,了解去哪里设置相应的环境变量十分重要

学完本章可以收获哪些内容?

(1)Linux环境变量的存储位置

(2)环境变量如何使用

(3)怎样创建自己的环境变量

6.1 什么是环境变量

bash shell用一个叫环境变量的特性来存储有关shell会话和工作环境的信息。这个特性允许我们在内存当中存储数据,以便程序或shell中运行的脚本能够轻松访问到他们。

在bash shell中,环境变量一般分为两类:

(1)全局变量

(2)局部变量

6.1.1 全局环境变量

全局环境变量对于shell会话和所有生成的子shell都是可见的。

局部环境变量只对创建他们的shell可见。

因此,只有全局环境变量才能使子shell获取父shell的信息

查看全局环境变量的命令:env 或 printenv

不带参数会列出所有的全局变量

[root@machine001 ~]# printenv HOME
/root

也可使用echo命令:

[root@machine001 ~]# echo $HOME
/root

6.1.2 局部变量变量

局部环境变量只能在定义他们的进程中可见。

Linux系统默认定义了标准的局部环境变量。

自己也可以定义,自己定义的局部变量被称为用户定义局部变量。

Linux系统并没有一个只显示局部环境 变量的命令。set命令会显示为某个特定进程设置的所有环境变量,包括局部变量、全局变量 以及用户定义变量

[root@machine001 ~]# set
...

6.2 设置用户定义变量

6.2.1 设置局部用户定义变量

一旦启动了bash shell,或者执行一个shell脚本,就可以创建这个shell进程内可见的局部变量,通过’='赋值,等号两端不能有空格,值可以是数值或字符串。

[root@machine001 ~]# echo $my_name

[root@machine001 ~]# my_name='mj'
[root@machine001 ~]# echo $my_name
mj

注:所有的环境变量名均使用大写字母,这是bash shell的标准惯例。如果自己要创建局部变量或者shell脚本,尽量使用小写字母。在涉及到用户定义的局部变量时,坚持使用小写字母,这能够避免重新定义系统环境变量可能带来的灾难。

6.2.2 设置全局环境变量

创建全局环境变量的方法是先创建一个局部环境变量,然后再把它导出到全局变量当中。

[root@machine001 ~]# my_name='global mj'
[root@machine001 ~]# export my_name
[root@machine001 ~]# echo $my_name
global mj
[root@machine001 ~]# bash
[root@machine001 ~]# echo $my_name
global mj

从上述命令我们可以看出,我们在父shell当中创建的局部变量导出到全局变量后,在子shell当中也可以取到该变量的值。

注:

(1)修改子shell中的全局变量不会影响父shell中该变量的值

(2)子shell无法使用export命令改变父shell中全局变量的值

6.3 删除环境变量

可以使用unset命令来删除环境变量:

[root@machine001 ~]# echo $my_name
global mj
[root@machine001 ~]# unset my_name
[root@machine001 ~]# echo $my_name

[root@machine001 ~]# 

工作小技巧:在涉及到环境变量名时,如何判断何时在变量名前加$?

(1)如果要使用变量,则加$

(2)如果操作变量(修改,删除),则不加$

(3)printenv 变量 这个命令操作例外

在删除全局变量时,需要注意:

如果在子进程当中删除了一个全局环境变量,那么这只对子进程有效,该全局变量在父进程当中仍然可用。

6.4 默认的shell环境变量

默认情况下,bash shell会用一些特定的环境变量来定义系统环境。这些变量在你的Linux系 统上都已经设置好了,可以直接使用。

默认的shell环境变量较多,这里就不一一列举,用到时自查就好。

6.5 设置 PATH 环境变量

当在shell命令行界面输入一个外部命令时,shell必须搜索系统来找到对应的程序。PATH环境变量定义了用于进行命令和程序寻找的目录。

[root@machine001 ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/module/jdk1.8.0_301/bin:/opt/module/hadoop/bin:/opt/module/hadoop/sbin:/opt/module/hive/bin:/opt/module/spark-yarn/bin:/root/bin

输出当中有10个可以供shell用来查找的命令和程序。PATH中的目录使用冒号分隔。

如果命令或者程序的位置没有包括在PATH变量中,那么如果不使用绝对路径的话,shell是没办法找到的。

[root@machine001 ~]# myprog
-bash: myprog: command not found

因此,为了解决该问题,我们可以向PATH环境变量中添加包含存放应用程序的目录

[root@machine001 ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/module/jdk1.8.0_301/bin:/opt/module/hadoop/bin:/opt/module/hadoop/sbin:/opt/module/hive/bin:/opt/module/spark-yarn/bin:/root/bin
[root@machine001 ~]# PATH=$PATH:/home/neu/bin
[root@machine001 ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/module/jdk1.8.0_301/bin:/opt/module/hadoop/bin:/opt/module/hadoop/sbin:/opt/module/hive/bin:/opt/module/spark-yarn/bin:/root/bin:/home/neu/bin
[root@machine001 ~]# test.sh 
majie

在将目录添加到PATH环境变量之后,就可以在虚拟目录结构中的任何地方执行程序。

注:如果希望子shell也能找到自己写的程序的位置,需要把修改后的PATH环境变量导出。

#JAVA_HOME
export JAVA_HOME=/opt/module/jdk1.8.0_301
export PATH=$PATH:$JAVA_HOME/bin

#HADOOP_HOME
export HADOOP_HOME=/opt/module/hadoop
export PATH=$PATH:$HADOOP_HOME/bin
export PATH=$PATH:$HADOOP_HOME/sbin

#HIVE_HOME
export HIVE_HOME=/opt/module/hive
export PATH=$PATH:$HIVE_HOME/bin

#SPARK_HOME
export SPARK_HOME=/opt/module/spark-yarn
export PATH=$PATH:$SPARK_HOME/bin

6.6 定位系统环境变量

在登入Linux系统启动一个bash shell时,默认情况下bash会在几个文件中查找命令。这些文件叫作启动文件或环境文件。bash检查的启动文件取决于你启动的bash shell的方式。启动bash shell有3种方式:

(1)登陆时作为默认登录shell

(2)作为非登录shell的交互式shell

(3)作为运行脚本的非交互shell

6.6.1 登录shell

当你登录Linux系统时,bash shell会作为登录shell启动。登录shell会从5个不同的启动文件里读取命令:

(1)/etc/profile

(2)$HOME/.bash_profile

(3)$HOME/.bashrc

(4)$HOME/.bash_login

(5)$HOME/.profile

/etc/profile文件是系统上默认的bash shell的主启动文件。系统上的每个用户登录时都会执行 这个启动文件。

6.6.1.1 /etc/profile文件

/etc/profile文件是bash shell默认的主启动文件,只要登录Linux系统,bash就会执行/etc/profile启动文件中的命令。下面注解里也提到,一般是不改动该文件内容的,想要添加环境或相关脚本,可以在/etc/profile.d/目录当中添加。

[root@machine001 etc]# cat 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/*目录下的.sh和sh.local这些脚本:

[root@machine001 profile.d]# ll
total 68
-rw-r--r--  1 root root  771 Sep 27  2018 256term.csh
-rw-r--r--  1 root root  841 Sep 27  2018 256term.sh
-rw-r--r--. 1 root root  196 Mar 25  2017 colorgrep.csh
-rw-r--r--. 1 root root  201 Mar 25  2017 colorgrep.sh
-rw-r--r--. 1 root root 1741 Apr 11  2018 colorls.csh
-rw-r--r--. 1 root root 1606 Apr 11  2018 colorls.sh
-rw-r--r--. 1 root root   80 Apr 11  2018 csh.local
-rw-r--r--  1 root root 1706 Sep 27  2018 lang.csh
-rw-r--r--  1 root root 2703 Sep 27  2018 lang.sh
-rw-r--r--. 1 root root  123 Jul 31  2015 less.csh
-rw-r--r--. 1 root root  121 Jul 31  2015 less.sh
-rw-r--r--  1 root root  377 Jan 26 11:57 my_env.sh
-rw-r--r--. 1 root root   81 Apr 11  2018 sh.local
-rw-r--r--  1 root root  105 Apr 11  2018 vim.csh
-rw-r--r--  1 root root  269 Apr 11  2018 vim.sh
-rw-r--r--. 1 root root  164 Jan 28  2014 which2.csh
-rw-r--r--. 1 root root  169 Jan 28  2014 which2.sh
6.6.1.2 $HOME目录下的启动文件

其他的启动文件都起着共同的作用:提供一个用户专属的启动文件来定义该用户所用到的环境变量。

大多数Linux发行版只用到这四个启动文件中的一个到两个:

(1)$HOME/.bash_profile

(2)$HOME/.bashrc

(3)$HOME/.bash_login

(4)$HOME/.profile

[root@machine001 ~]# ls -a | grep -e "bash" -e "profile"
.bash_history
.bash_logout
.bash_profile
.bashrc

注:以.号开头的文件说明是隐藏文件

shell会按照下列顺序,运行第一个被找到的文件,余下的则会被忽略:

$HOME/.bash_profile

$HOME/.bash_login

$HOME/.profile

注:这个列表中并没有$HOME/.bashrc文件。这是因为该文件通常通过其他文件运行的。

[root@machine001 ~]# cat .bash_profile 
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
	. ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/bin

export PATH
[root@machine001 ~]# 

.bash_profile启动文件会先去检查HOME目录中是不是还有一个叫.bashrc的启动文件。如果有 的话,会先执行启动文件里面的命令。

注:$HOME 和 ~ 的作用相同。

6.6.2 交互式shell进程

如果你的bash shell不是登录系统时启动的(比如是在命令行提示符下敲入bash时启动),那 么你启动的shell叫作交互式shell。

如果bash是作为交互式shell启动的,那么它不会访问/etc/profile文件,只会检查用户HOME目录中的.bashrc文件

[root@machine001 ~]# cat .bashrc 
# .bashrc

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# Source global definitions
if [ -f /etc/bashrc ]; then
	. /etc/bashrc
fi

bashrc文件有两个作用:一是查看/etc目录下通用的bashrc文件,二是为用户提供一个定制自己的命令别名和私有脚本函数的地方。

6.6.3 非交互式shell

系统执行shell脚本时用的就是这种shell。不同的地方在于它没有命令行提示符。但是当你在系统上运行脚本时,也许希望能够运行一些特定启动的命令。

为了处理这种情况,bash shell提供了BASH_ENV环境变量。当shell启动一个非交互式shell进程时,它会检查这个环境变量来看要执行的启动文件。如果有指定的文件,shell会执行该文件里的命令,这通常包括shell脚本变量设置。

在CentOS Linux发行版当中,该变量默认情况下并没有设置,那shell脚本应该到哪里去获取它们的环境变量呢?

有些shell脚本是通过启动一个子shell来执行的,子shell可以继承父shell导出的变量

例如:父shell是登录shell,在/etc/profile、/etc/profile.d/*.sh和$HOME/.bashrc文件中 设置并导出了变量,用于执行脚本的子shell就能够继承这些变量。

注:由父shell设置但并未导出的变量都是局部变量。子shell无法继承局部变量。

对于那些不启动子shell的脚本,**变量已经存在于当前shell中了。**所以就算没有设置 BASH_ENV,也可以使用当前shell的局部变量和全局变量。

6.6.4 环境变量持久化

Q:如何创建通用的永久性全局变量或局部变量?

A:最好是在**/etc/profile.d目录中创建一个以.sh结尾的文件**。把所有新的或修改过的全局环境变量设置放在这个文件中。

Q:存储个人用户永久性bash shell变量的地方?

A:$HOME/.bashrc文件

6.7 数组变量

环境变量有一个很酷的特性就是,它们可作为数组使用。数组是能够存储多个值的变量。这些值可以单独引用,也可以作为整个数组来引用。 要给某个环境变量设置多个值,可以把值放在括号里,值与值之间用空格分隔。

[root@machine001 ~]# test=(one two three)
[root@machine001 ~]# echo $test
one
[root@machine001 ~]# echo $test[1]
one[1]
[root@machine001 ~]# echo ${test[1]}
two
[root@machine001 ~]# 

注:索引值需要用方括号括起来,然后需要用花括号进行解析

要显示整个数组变量,可用星号作为通配符放在索引值的位置。

[root@machine001 ~]# echo ${test[*]}
one two three

也可以使用uset删除数组中某个值

[root@machine001 ~]# unset test[0]
[root@machine001 ~]# echo ${test[*]}
two three

数组变量这个特性在shell脚本编程时不常用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值