Shell在Linux中具有相当重要的地位,利用shell可以实现Linux系统的自动化管理。本文以bash shell为主,来介绍shell变量。
1. Shell的父子关系
通常,登录某个远程终端或在GUI中运行终端仿真器时所启动的默认的交互shell,是我们在其中运行操作命令的父shell,这个shell提供一个CLI提示符,等待用户的命令输入。而我们在CLI中执行的命令或脚本等都是该父shell的子shell。例如,在CLI中输入bash之后会产生一个新的shell,并具有一个新的进程号。
ubuntu@localhost:~$ ps -f
UID PID PPID C STIME TTY TIME CMD
ubuntu 99804 99803 0 20:45 pts/1 00:00:00 -bash
ubuntu 99965 99804 0 21:34 pts/1 00:00:00 ps -f
ubuntu@localhost:~$ bash
ubuntu@localhost:~$ ps -f
UID PID PPID C STIME TTY TIME CMD
ubuntu 99804 99803 0 20:45 pts/1 00:00:00 -bash
ubuntu 99966 99804 1 21:34 pts/1 00:00:00 bash
ubuntu 99978 99966 0 21:34 pts/1 00:00:00 ps -f
以下图中多次输入bash,来产生一个子shell显示的现象(当然也可以用其他命令代替,只要产生的子shell不会很快退出即可)。
ubuntu@localhost:~$ ps -f
UID PID PPID C STIME TTY TIME CMD
ubuntu 99804 99803 0 20:45 pts/1 00:00:00 -bash
ubuntu 99980 99804 0 21:35 pts/1 00:00:00 ps -f
ubuntu@localhost:~$ bash
ubuntu@localhost:~$ bash
ubuntu@localhost:~$ bash
ubuntu@localhost:~$ ps --forest
PID TTY TIME CMD
99804 pts/1 00:00:00 bash
99981 pts/1 00:00:00 \_ bash
99993 pts/1 00:00:00 \_ bash
100005 pts/1 00:00:00 \_ bash
100017 pts/1 00:00:00 \_ ps
下图为父shell创建子shell的过程示意图:
2. 变量
在Shell中,变量同样分为环境变量和普通变量。全局变量对于当前Shell和所有生成的子Shell都可见,局部变量只对创建它们的Shell可见。在shell脚本中,默认的有如下变量可以直接拿来使用:
变量 | 说明 |
---|---|
$0 | 当前所执行shell脚本名称 |
$n | shell脚本后所跟的参数,n表示第几个参数 |
$# | 获得命令行参数个数 |
$* | 获得所有命令行参数,将其视为一个整体 |
$@ | 获得所有命令行参数,将其视为多个独立的字符串 |
$? | 判断上一条命令是否执行成功,若成功,则返回0 |
$$ | 当前进程的PID |
$! | 上一个进程的PID |
$_ | 上一条命令的参数 |
变量名通常使用“$name”的形式来表示,如$var、$PATH等,也可以采用“${name}”的方式进行表示。两者的效果是等价的,前者是后者的简写形式,但在某些情况下,后一种表示方式是可用的,前一种方式会产生歧义。
例如,$n在使用过程中是shell脚本具体的执行参数,n表示第几个参数,那么$1、$2…$9,等都可以正常使用,但从$10开始就会发生问题。shell会认为并不是指的第10个变量,而是$1+0,也就是第一个变量后面和0一起组成的字符串,所以此时就需要使用${10}的方式表示。
3. 普通变量(局部变量)
局部变量只对创建它们的shell可见,即在定义它们的进程中可见。对系统的局部变量查看,只能采用set命令,set命令会显示为某个特定进程设置的所有环境变量,包括局部变量、全局变量以及用户定义变量。如下所示(因为set显示内容太多,所以这里仅列出10行):
ubuntu@localhost:~$ set |head
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_com
ments:login_shell:progcomp:promptvars:sourcepathBASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_COMPLETION_COMPAT_DIR=/etc/bash_completion.d
BASH_LINENO=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="4" [1]="3" [2]="48" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")
在Linux中,shell变量的设置规则如下:
1.变量名由大小写字母、数字和下划线(_)组成,但不能以数字开头
2.通过等号(=)为变量分配值,等号两边不能有空格
3.变量存储的数据类型是整数值和字符串值
4.在对变量赋于字符串值时,建议使用引号将其包裹。
5.若变量名存在空格,要使用单引号或双引号将所有内容括起来,或者对空格转义。
以下对于局部变量的设置举例如下:
1.在直接查看一个没有定义的变量时,不会有任何输出,在定义之后可正常显示:
ubuntu@localhost:~$ echo $var
ubuntu@localhost:~$ var=hello
ubuntu@localhost:~$ echo $var
hello
2.在使用引号时,单引号会直接将内容原样输出,双引号会使用变量内容对变量所在位置进行替换:
ubuntu@localhost:~$ echo '$var Tom'
$var Tom
ubuntu@localhost:~$ echo "$var Tom"
hello Tom
- 变量内容中存在空格时,可以利用引号括起来或使用转义:
ubuntu@localhost:~$ var=hello world
No command 'world' found, did you mean:
Command 'tworld' from package 'tworld' (universe)
world: command not found
ubuntu@localhost:~$ var='hello world'
ubuntu@localhost:~$ echo $var
hello world
ubuntu@localhost:~$ var=hello\ world\ test
ubuntu@localhost:~$ echo $var
hello world test
4. 环境变量(全局变量)
环境变量也就是全局变量,全局环境变量对于shell会话和所有生成的子shell都是可见的。在Linux系统中有很多环境变量,均以大写字母的方式命名,而且Bash会通过环境变量来存储和有关shell会话和工作环境的信息。例如,查看特定的全局变量:
ubuntu@localhost:~$ echo $LANG
en_US.UTF-8
ubuntu@localhost:~$ echo $HOME
/home/ubuntu
ubuntu@localhost:~$ echo $PATH
/home/ubuntu/bin:/home/ubuntu/.local/bin:/usr/local/sbin:
/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/loc
al/games:/snap/bin
ubuntu@localhost:~$ echo $SHELL
/bin/bash
ubuntu@localhost:~$ echo $USER
ubuntu
使用printenv或env查看当前用户所有全局变量:
buntu@localhost:~$ env
LC_PAPER=zh_CN.UTF-8
LC_ADDRESS=zh_CN.UTF-8
XDG_SESSION_ID=71
LC_MONETARY=zh_CN.UTF-8
TERM=xterm
SHELL=/bin/bash
SSH_CLIENT=192.168.254.1 57768 22
LC_NUMERIC=zh_CN.UTF-8
SSH_TTY=/dev/pts/6
USER=ubuntu
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=3
0;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:LC_TELEPHONE=zh_CN.UTF-8
MAIL=/var/mail/ubuntu
PATH=/home/ubuntu/bin:/home/ubuntu/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/us
r/local/games:/snap/binQT_QPA_PLATFORMTHEME=appmenu-qt5
LC_IDENTIFICATION=zh_CN.UTF-8
PWD=/home/ubuntu
LANG=en_US.UTF-8
LC_MEASUREMENT=zh_CN.UTF-8
SHLVL=1
HOME=/home/ubuntu
LOGNAME=ubuntu
XDG_DATA_DIRS=/usr/local/share:/usr/share:/var/lib/snapd/desktop
SSH_CONNECTION=192.168.254.1 57768 192.168.254.130 22
LESSOPEN=| /usr/bin/lesspipe %s
XDG_RUNTIME_DIR=/run/user/1000
DISPLAY=localhost:12.0
LESSCLOSE=/usr/bin/lesspipe %s %s
LC_TIME=zh_CN.UTF-8
LC_NAME=zh_CN.UTF-8
_=/usr/bin/env
ubuntu@localhost:~$
对于全局变量的设置,一般先创建一个局部变量,再利用export命令设置为全局变量,unset命令删除全局变量。举例如下:
1.全局变量设置之后对当前进程以及子进程都生效:
ubuntu@localhost:~$ echo $VAR
ubuntu@localhost:~$ VAR='variance test'
ubuntu@localhost:~$ echo $VAR
variance test
ubuntu@localhost:~$ export VAR
ubuntu@localhost:~$ bash
ubuntu@localhost:~$ echo $VAR
variance test
ubuntu@localhost:~$ exit
exit
ubuntu@localhost:~$ echo $VAR
variance test
2.在子进程中修改全局变量的值,对父进程不影响:
ubuntu@localhost:~$ VAR='variance test2'
ubuntu@localhost:~$ echo $VAR
variance test2
ubuntu@localhost:~$ bash
ubuntu@localhost:~$ echo $VAR
variance test2
ubuntu@localhost:~$ VAR='variance child test'
ubuntu@localhost:~$ echo $VAR
variance child test
ubuntu@localhost:~$ exit
exit
ubuntu@localhost:~$ echo $VAR
variance test2
- 删除全局变量:
ubuntu@localhost:~$ echo $VAR
variance test2
ubuntu@localhost:~$ unset VAR
ubuntu@localhost:~$ echo $VAR
5. 应用举例
- 设置PATH环境变量(添加新的命令搜索路径,以/tmp/test为例):
ubuntu@localhost:~$ echo $PATH
/home/ubuntu/bin:/home/ubuntu/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/binubuntu@localhost:~$
ubuntu@localhost:~$ mkdir /tmp/test
ubuntu@localhost:~$
ubuntu@localhost:~$ PATH=$PATH:/tmp/test
ubuntu@localhost:~$ echo $PATH
/home/ubuntu/bin:/home/ubuntu/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/tmp/test
ubuntu@localhost:~$ export PATH
2.登陆shell环境变量配置文件说明
/etc/profile文件是bashshell默认的主启动文件,只要登录Linux系统,就会执行/etc/profile文件中命令。在/etc/profile文件中存在for循环语句迭代/etc/profile.d目录下的所有文件。并且,在用户HOME下存在 H O M E / . b a s h r c , HOME/.bashrc, HOME/.bashrc,HOME/.bash_login, H O M E / . b a s h h i s t o r y , HOME/.bash_history, HOME/.bashhistory,HOME/.profile等文件,会依次按顺序查找运行。最后,会使用/etc/bash.bashrc文件。整体流程如下:/etc/profile–>/etc/profile.d/*.sh–>~/.bashrc–>/etc/bash.bashrc
3.将命令执行结果赋值给变量使用(两种方式,利用反引号或括号):
ubuntu@localhost:~$ echo $var
hello world test
ubuntu@localhost:~$ grep UID_MIN /etc/login.defs |grep -v '^#' |awk '{print $2}'
1000
ubuntu@localhost:~$ var=`grep UID_MIN /etc/login.defs |grep -v '^#' |awk '{print $2}'`
ubuntu@localhost:~$ echo $var
1000
ubuntu@localhost:~$
ubuntu@localhost:~$ date
2020年 01月 01日 星期三 22:09:34 CST
ubuntu@localhost:~$ var=$(date)
ubuntu@localhost:~$ echo $var
2020年 01月 01日 星期三 22:09:50 CST
参考文档:
https://www.cnblogs.com/diantong/p/10805727.html
《Linux命令行与Shell脚本编程大全(第三版)》