5、Shell变量

变量分类

变量可分为2类:环境变量(全局变量)和局部变量(本地变量)。

环境变量可以在创建他们的shell及其派生出来的任意子进程shell中使用。局部变量只能在创建他们的shell函数或脚本中使用。

命名规范:

一般是字母、数字、下划线组成,必须以字母开头。

语义要清晰,能够正确表达变量内容的含义,过长的英文单词可采用前几个字符代替。多个单词用"_"连接。

避免无含义的字符或数字。

环境变量

(1)概念

环境变量用于定义Shell的运行环境,保证Shell命令的正确执行。所有环境变量都是系统全局变量,可用于所有子进程中。

环境变量可以在命令行中设置,但用户退出时这些变量值也会丢失,因此,最好在用户home目录下的.bash_profile或.bashrc(非用户登录特有,例如SSH)文件中,或全局配置文件/etc/bashrc(非用户登录特有,例如SSH)或/ect/profile,在每次用户登录时将其初始化

根据规范,所有环境变量应均为大写。在用于用户进程前,必须用export命令抛出

使用习惯:一般数字不加引号,其它默认加双引号。

(2)查看系统所有环境变量

  • a、env命令显示全局变量
[root@CentOS8 test]# env
HOSTNAME=lamp
TERM=linux
SHELL=/bin/bash
HISTSIZE=1000
  • b、set输出所有的变量,包括全局变量和局部变量
[root@CentOS8 test]# set
BASH=/bin/bash
...
HISTCONTROL=ignoredups
HISTFILE=/root/.bash_history
HISTFILESIZE=1000
...

(3)设置和临时生效自定义环境变量

如果想设置环境变量,就要在给变量赋值之后或在设置变量时使用export命令。

  • a、export命令设置
变量名=value;
export 变量名
或
export 变量名=value
  • b、declare  -x命令设置,该命令单独使用会输出所有的变量、函数、整数和已经到处的变量
declare -x 变量名=value
  • c、示例
[root@inspur ~]# abc=20
[root@inspur ~]# export abc
[root@inspur ~]# export abd=30
[root@inspur ~]# declare -x abe=40

(4)永久生效自定义环境变量(别名alias也是一样)

  • a、全局生效(所有用户)
vi /etc/profile  或 vi /etc/bashrc
export abc = 20
  • b、当前用户生效
vi ~/.bashrc  或 vi ~/.bash_profile
export abc = 20

(5)设置登录提示的两种方式

  • 1./etc/profile.d/方式定义环境变量
vi /etc/profile.d/test.sh
echo "This is /etc/profile.d/test.sh...."
export TEST_ABC=30
chmod +x /etc/profile.d/test.sh  # 可执行权限
logout
回车登入
Last login: Sat May  6 11:53:28 2017 from 192.168.1.11
This is /etc/profile.d/test.sh....
[root@lamp ~]# echo $TEST_ABC
30
  • 2.此种方法可以作为设置登录提示的方式,下面还有一种:
[root@CentOS8 ~]# cat /etc/motd
welcome to boxiaoyuan linux shell

对于用户的环境变量设置,比较常见的是用户家目录下的.bashrc和.bash_profile。

(6)显示和取消环境变量

  • a、通过echo命令打印环境变量
[root@CentOS8 ~]# echo $HOME
/root
  • b、通过printf命令打印环境变量(需在结尾加\n,显示的格式比echo丰富)
[root@CentOS8 ~]# printf "$HOME\n"
/root
  • c、通过unset命令取消环境变量(此时不要带$)
[root@CentOS8 ~]# echo $TEST_ABC
30
[root@CentOS8 ~]# unset TEST_ABC
[root@CentOS8 ~]# echo $TEST_ABC

[root@CentOS8 ~]# 

(7)环境变量知识小结

  • 变量名通常大写
  • 变量可以在自身的Shell及子Shell中使用。
  • 常用export来定义环境变量
  • 执行env默认可以显示所有的环境变量名称及对应的值
  • 输出时用“$变量名”,取消时用“unset 变量名”
  • 书写crond定时任务时要注意,脚本要用到的环境变量最好先在所执行的Shell脚本中重新定义。
  • 如果希望环境变量永久生效,可以将其放在用户环境变量文件或全局环境变量文件中。

(8)环境变量初始化与对应文件的生效顺序

系统运行Shell的方式有三种

  • 1)系统用户登录后默认运行的Shell
  • 2)非登录交互式运行Shell
  • 3)执行脚本运行非交互式Shell

用户登录linux,shell会作为登录shell启动,此时shell加载环境变量的顺序:首先加载/etc/profile全局环境变量文件,然后执行/etc/profile.d目录下的脚本文件,之后开始运行$HOME/.bash_profile(用户环境变量文件),在这个文件中,又会去$HOME/.bashrc(用户环境变量文件),如果有,则执行,没有,则不执行,在$HOME/.bashrc文件中又会找/etc/bashrc(全局环境变量文件),如果有执行,如果没有,则不执行。

 

如果用户的Shell不是登录时启动(比如手动敲下bash时启动或其他不需要输入密码的登录及远程SSH连接),这种非登录Shell只会加载$HOME/.bashrc(用户环境变量文件),并会去找/etc/bashrc(全局环境变量文件)。因此如果希望在非登录shell下也可以读到设置的环境变量等内容,就需要将变量设定等写入$HOME/.bashrc或者/etc/bashrc。

局部变量

(1)概念

局部变量又称本地变量,只在用户当前的Shell生存期的脚本中使用。如果在Shell中启动另一个进程或退出,则本地变量的值将无效。

(2)定义局部变量

  • a、普通字符串变量定义
变量名=value
变量名='value'
变量名="value"
  • b、命令变量定义
变量名=``
变量名=$()
  • c、函数中变量定义
local 变量名
local 变量名=value

一定要用local方式进行声明,使之只在本函数作用域内有效,防止变量在函数中命名与变量外部程序中变量重名,造成程序异常。

(3)示例1:命令行输入下列命令返加什么结果

[root@CentOS8 ~]# a=192.168.1.2
[root@CentOS8 ~]# b='192.168.1.2'
[root@CentOS8 ~]# c="192.168.1.2"
[root@CentOS8 ~]# echo "a=$b"
a=192.168.1.2
[root@CentOS8 ~]# echo "c=${c}" 
c=192.168.1.2

提示:$c与${c}在这里是等同的

小结:将连接普通字符串的内容赋值给变量,打印变量时,是原样输出。

(4)示例2:命令行输入下列命令返加什么结果

[root@CentOS8 ~]# a=192.168.1.2
[root@CentOS8 ~]# a=192.168.1.2-$a
[root@CentOS8 ~]# b='192.168.1.2-$a'
[root@CentOS8 ~]# c="102.168.1.2-$a"
[root@CentOS8 ~]# echo "a=$a"
a=192.168.1.2-192.168.1.2
[root@CentOS8 ~]# echo "b=$b"
b=192.168.1.2-$a
[root@CentOS8 ~]# echo "c=${c}"
c=102.168.1.2-192.168.1.2-192.168.1.2

小结:

单引号“'”是原样输出,不论引号内有什么,即使引号有变量,也会把变量名原样输出。适用于定义纯字符串。

双引号““”中的内容是会被解析的,将引号中的变量解析成该变量的内容结果输出。适用于字符串中附带有变量的内容的定义。

(5)单引号、双引号和无引号的区别

  • (1)单引号

所见即所得,将单引号内的所有内容都不解析,原样输出。

  • (2)双引号

输出双引号中的所有内容。如果引号中有命令(反引号中)、变量、特殊转义符等,就会先解析变量,将解析结果输出到最终内容中。

  • (3)无引号

类似于双引号,把解析结果输出到最终内容中,但如果字符串中带有空格等特殊字符,则不能完整的输出,需要加上双引号。最好用双引号代替无引号。一般脚本中单纯的数字可以不加引号,普通字符串尽量用双引号。

  • (4)注意事项

对某些语言不适合,如awk内部就有特殊规定(单、双引号正好与shell中相反)。

  • (5)示例1:awk调用数据型shell变量
[root@CentOS8 ~]# ETT=123
[root@CentOS8 ~]# echo $ETT
123
[root@CentOS8 ~]# awk 'BEGIN {print "$ETT"}'
$ETT
[root@CentOS8 ~]# awk 'BEGIN {print '$ETT'}'
123
[root@CentOS8 ~]# awk 'BEGIN {print $ETT}'

[root@CentOS8 ~]# 
  • (6)示例2:awk调用字符型shell变量
[root@CentOS8 ~]# ETT='abc'
[root@CentOS8 ~]# echo $ETT
abc
[root@CentOS8 ~]# awk 'BEGIN {print "$ETT"}'
$ETT
[root@CentOS8 ~]# awk 'BEGIN {print '$ETT'}'

[root@CentOS8 ~]# awk 'BEGIN {print $ETT}'  

[root@CentOS8 ~]# awk 'BEGIN {print "'$ETT'"}'
abc

总结:不管变量如何定义,赋值,除了单引号以外,利用awk直接获取变量的输出,结果都是一样的,因此在awk取用shell变量时,我们更多的还是喜欢先用echo加符号输出变量,然后通过管道给awk,进而控制变量的输出结果。

[root@CentOS8 ~]# ETT="boxiaoyuan"
[root@CentOS8 ~]# echo $ETT | awk '{print $0}'
boxiaoyuan
[root@CentOS8 ~]# echo "$ETT" | awk '{print $0}'
boxiaoyuan
[root@CentOS8 ~]# echo '$ETT' | awk '{print $0}'  
$ETT
[root@CentOS8 ~]# ETT=`pwd`
[root@CentOS8 ~]# echo $ETT | awk '{print $0}'
/root
[root@CentOS8 ~]# echo "$ETT" | awk '{print $0}'
/root
[root@CentOS8 ~]# echo '$ETT' | awk '{print $0}'  
$ETT

(6)把一个命令的结果作为变量的内容赋值方法

变量名=`ls` #<==把命令用反引号引起来,不推荐使用这种方法,因为容易和单引号混淆

变量名=$(ls) #<==把命令用$()括起来,推荐使用这种方法

[root@CentOS8 ~]# CMD=$(date +%F)   #<==将当前日期赋值给CMD变量
[root@CentOS8 ~]# echo $CMD   #<==输出变量的值
2020-08-22
[root@CentOS8 ~]# ECHO $(date +%F).tar.gz   #<==直接输出时间命令的结果
bash: ECHO: command not found...
Similar command is: 'echo'
[root@CentOS8 ~]# echo $(date +%F).tar.gz    
2020-08-22.tar.gz
[root@CentOS8 ~]# echo `date +%F`.tar.gz
2020-08-22.tar.gz
[root@CentOS8 ~]# tar zcf etc_$(date +%F).tar.gz /server/files
tar: Removing leading `/' from member names
[root@CentOS8 ~]# ls -l etc_2020-08-22.tar.gz 
-rw-r--r-- 1 root root 118 Aug 22 08:18 etc_2020-08-22.tar.gz
[root@CentOS8 ~]# H=$(uname -n)
[root@CentOS8 ~]# echo $H
CentOS8
[root@CentOS8 ~]# tar zcvf $(uname -n).tar.gz /server/files/  #<==将主机作为压缩包
tar: Removing leading `/' from member names
/server/files/
[root@CentOS8 ~]# ll CentOS8.tar.gz 
-rw-r--r-- 1 root root 118 Aug 22 08:19 CentOS8.tar.gz

(7)局部变量定义及赋值小结

如果变量内容为连续的数字或字符串,赋值时可以不加引号;如果内容多且有空格且想解析内容中的变量,就加双引号;如果想原样输出变量中内容,就加单引号。

(8)变量的输出方法小结

使用“$变量名”即可输出变量内容,常用“echo $变量名”的方式

$dbname_tname,当变量后面连接有其他字符发时候,必须给变量加上大括号{},如${dbname}_tname。

Shell特殊变量

(1)位置变量

  • a、$0:获取当前执行的shell脚本的文件名,如果执行脚本带路径,则包含脚本路径。

(i)示例1

[root@CentOS8 ~]# cat 1.sh 
echo $0
[root@CentOS8 ~]# sh 1.sh 
1.sh
[root@CentOS8 ~]# sh $(pwd)/1.sh
/root/1.sh
  • b、$n:获取当前执行的shell脚本的第n个参数值,n>1,如果n>9时,则需用大括号括起来,如${10}。

(i)示例1

[root@CentOS8 ~]# cat 3.sh 
echo $1
[root@CentOS8 ~]# sh 3.sh 

[root@CentOS8 ~]# sh 3.sh aaa
aaa
[root@CentOS8 ~]# sh 3.sh aaa bbb
aaa
[root@CentOS8 ~]# sh 3.sh "aaa bbb"
aaa bbb

(ii)示例2

[root@Centos8 ~]# echo $(echo -n 'echo $1 ' && echo '$'{2..15})>4.sh
[root@inspur ~]# cat 4.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
[root@Centos8 ~]# sh 4.sh {a..z}
a b c d e f g h i a0 a1 a2 a3 a4 a5
[root@Centos8 ~]# echo $(echo 'echo $1' && echo '$'{2..9} && echo '${'{10..15}'}')>4.sh
[root@Centos8 ~]# cat 4.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15}
[root@Centos8 ~]# sh 4.sh {a..z}                         
a b c d e f g h i j k l m n o
  • c、$#:获取当前执行的shell命令行中参数的总个数。

(i)示例1

[root@CentOS8 test]# echo 'echo $#' > 5.sh
[root@CentOS8 test]# cat 5.sh 
echo $#
[root@CentOS8 test]# sh 5.sh {a..z}
26

(ii)示例2

[root@CentOS8 test]# cat 6.sh 
[ $# -ne 2 ] && {
        echo "must two"
        exit 1
}
echo 'OK'
[root@CentOS8 test]# sh 6.sh 
must two
[root@CentOS8 test]# sh 6.sh aaa bbb
OK
[root@CentOS8 test]# sh 6.sh aaa bbb ccc
must two
  • d、$*:获取当前执行的shell的所有参数,但将命令行的所有参数视为一个字符串。相当于"$1$2$3.."。
  • e、$@:获取当前执行的shell的所有参数,是将命令行的所有参数视为一个个的单个个体,以"$1" "$2" "$3" "$4"...形式获取,这是将参数传递给其它程序的最佳方式。
  • f、$*与$@的区别

(i)示例1:有双引号        

[root@CentOS8 test]# set -- "I am" handsome test  <--#以set方式来模拟传入3个参数
[root@CentOS8 test]# echo $#
3   <--#当前共传入3个参数
[root@CentOS8 test]# for i in "$*";do echo $i;done
I am handsome test   <--#$*将3个参数视为1个参数
[root@CentOS8 test]# for i in "$@";do echo $i;done   <--#$*3个参数还是认为是3个参数
I am
handsome
test

(ii)示例2:无引号($*与$@效果一样)

[root@CentOS8 test]# for i in $*;do echo $i;done  
I
am  <--#将第1个参数“I am”也折分了
handsome
test
[root@CentOS8 test]# for i in $@;do echo $i;done  
I
am
handsome
test

常用的特殊位置参数变量说明

位置变量 作用说明
$0 获取当前执行的Shell脚本的文件名,如果执行脚本包含了路径,那么就包含脚本路径
$n 获取当前执行的Shell脚本的第n个参数值,n=1..9,当n为0时表示脚本的文件名;当n大于9时,则用大括号括起来,例如${10},借的参数以空格隔开
$# 获取当前执行的Shell脚本后面接的参数的总个数
$* 获取当前Shell脚本所有传参的参数,不加引号和$a相同;如果$*加上双引号,例如:“$*”,则表示将所有的参数视为单个字符串,相当于”$1$2$3”
$@ 获取当前Shell脚本所有传参的参数,不加引号和$*相同;如果给$@加上双引号,例如:“$@”,则表示将所有的参数视为不同的独立字符串,相当于”$1””$2”…。这是将多参数传递给其他程序的最佳方式,以内它会保留所有的内嵌在每个参数里的任何空白。”$@”和”$*”都加双引号时,两者是有区别的;都不加双引号时,两者无区别。

(2)进程状态变量

Shell进程的特殊状态变量说明

位置变量 作用说明
$? 获取执行上一个指令的执行状态返回值(0为成功,非零为失败),这个变量最常用
$$ 获取当前执行的Shell脚本进程号(PID),这个变量不常用,了解即可
$! 获取上一个在后台工作的进程的进程号(PID),这个变量不常用,了解即可
$_ 获取在此之前执行的命令或脚本的最后一个参数,这个变量不常用,了解即可

Shell内置命令

常用的内部的命令:echo、eval、exec、export、read、shift。

  • (1)echo将命令后面args指定的字符串及变量等显示到标准输出
    • -n 不换行输出内容 
    • -e 解析转义字符(见下面)
    • \n   换行  \r   回车  \t 制表符  \b  退格  \v 纵向制表符
[root@CentOS8 test]# echo boxiaoyuan;echo zhangsan
boxiaoyuan
zhangsan
[root@CentOS8 test]# echo -n boxiaoyuan;echo shangzan
boxiaoyuanshangzan
[root@CentOS8 test]# echo "boxiaoyuan\tzhangsan"
boxiaoyuan\tzhangsan
[root@CentOS8 test]# echo -e "boxiaoyuan\tzhangsan"
boxiaoyuan      zhangsan
  • (2)eval:当Shell程序执行到eval语句时,Shell读入参数args,并将他们组合成一个新的命令,然后执行。
  • (3)exec:在不创建新的子进程的前提下,转去执行指定的命令,当指定的命令执行完毕后,该进程就终止了
  • (4)read从标准输入读取字符串等信息,传给Shell程序内部定义的变量
  • (5)移动位置变量的命令shift
    • a、说明:将后面的变量位置依次往前移动。不指定位移量的默认情况下每次前移1个位置。每执行一次shift命令,都会使所有位置的参数依次向左移动1个位置(默认),并使位置参数$#减1,直至0为止。
    • 作用:就是方便。
  • (6)exit 退出Shell程序,在shell之后可以有选择的制定一个数位作为返回状态。
posted @ 2020-08-20 07:09  博小园  阅读(215)  评论(0编辑  收藏  举报
回到顶部