Shell 变量基础知识
变量是暂时存储数据的地方及数据标记,所存储的数据存在于内存空间中,通过正确地调用内存空间中变量的名字就可以取出与变量对应的数据。
变量的内容一般要加双引号,以防止出错,特别是当值里的内容之间有空格时。
# 赋值变量:变量名=xxx[root@localhost ~18:56:59]# name="123456"# 加$[root@localhost ~18:58:49]# echo $name123456变量类型
变量根据范围可分为两类:
- 全局变量,在创建它们的 Shell及其派生出来的任意子进程 Shell 中使用。
- 局部变量,只能在创建它们的 Shell 函数或 Shell 脚本中使用。
变量根据是否是用户自定义也可分为两类:
- 普通变量:也称为常规变量,由开发者在开发脚本程序时创建。
- 环境变量:定义shell 执行环境。环境变量又可分为自定义环境变量和bash内置的环境变量。
环境变量
环境变量一般是指用export内置命令导出的变量,用于定义 Shell 的运行环境,保证 Shell 命令的正确执行。Shell 通过环境变量来确定登录用户名、命令路径、终端类型、登录目录等,所有的环境变量都是系统全局变量,可用于所有子进程中,这包括编辑器、 Shell 脚本和各类应用。
环境变量可以在命令行中设置和创建,但用户退出命令行时这些变量值就会丢失,因此,如果希望永久保存环境变量,可在用户家目录下的.bash_profile或.bashrc(非用户登录模式特有,例如远程SSH)文件中,或者全局配置/etc/bashrc(非用户登录模式特有,例如远程SSH)或/etc/profile文件中定义。在将环境变量放入上述的文件中后,每次用户登录时这些变量都将被初始化。
按照系统规范,所有环境变量的名字均采用大写形式。在将环境变量应用于用户进程程序之前,都应该用export命令导出定义。有一些环境变量,比如HOME、PATH、USER等,在用户登录之前就已经被/bin/login程序设置好了。通常环境变量被定义并保存在用户家目录下的.bash_profile文件或全局的配置文件/etc/profile中。
部分bash环境变量展示:
- EDITOR,默认编辑器。
- HISTFILE,历史文件位置。
- HISTSIZE,历史命令个数。
- HISTTIMEFORMAT,history历史命令显示格式。
- PS1,命令行提示符。
- LANG,Shell 环境语言。
- PATH,命令搜素路径。
- HOME,当前用户家目录。
- USER,当前用户的用户名。
- UID,当前用户的用户ID。
- PWD,当前 Shell 路径。
- IFS,字符串分隔符。
在查看设置的变量时,有3个命令可以显示变量的值:
- set 命令,输出所有的变量,包括全局变量和局部变量。
- env 命令,只显示全局变量,包括 shell 的环境。
- declare 命令,输出所有的变量、函数、整数和已经导出的变量。
set -o命令显示bash Shell 的所有参数配置信息。
设置环境变量
1. 设置环境变量
如果想要设置环境变量,就要在给变量赋值( value )之后或在设置变量时使用export命令,具体设置见下文的示例。其实,除了export命令,带-x选项的declare内置命令也可以完成同样的功能
注意:此处不要在变量名前面加$。
export命令和declare命令的格式如下:
export 变量名=value变量名=value ; export 变量名declare -x 变量名=value
示例:
exportNAME=csrdeclare-xNAME=csrNAME=csr;exportNAME下面来看看让环境变量永久生效的常用设置文件。
- 用户的环境变量配置文件:
~/.bash_profile和~/.bashrc。推荐在(~/.bashrc)文件中设置。 - 全局环境变量的配置文件:
/etc/profile、/etc/bashrc、/etc/profile.d/。**推荐在 /etc/bashrc 文件中设置。**若要在登录后初始化或显示加载内容,则把脚本文件放在/etc/profile.d/下即可(无须加执行权限)。
2. 设置登录后提示信息
第一种是在
/etc/motd里增加提示的字符串,如下:[root@localhost ~20:53:49]# vim /etc/motdwelcome to csr linux Shell training.登录后:
第二种是在 /etc/profile.d/ 下面增加如下脚本。
[root@localhost ~ 20:57:39]# vim /etc/profile.d/csr.sh echo welcome to csr linux Shell training.补充:
- 登录前提示符由文件 /etc/issue 提供。
- 上一次登录记录由ssh服务提供:在
/etc/ssh/sshd_config文件中配置PrintLastLog yes,默认启用。
显示与取消环境变量
- 用
echo或printf命令打印环境变量。 - 用
env或set显示默认的环境变量。 - 用
unset消除本地变量和环境变量。
环境变量小结
- 变量名通常要大写。
- 变量可以在自身的 Shell 及子 Shell 中使用。
- 常用
export来定义环境变量。 - 执行
env默认可以显示所有的环境变量名称及对应的值。 - 输出时用
$变量名,取消时用unset变量名。 - 书写
crond定时任务时要注意,脚本要用到的环境变量最好先在所执行的 Shell 脚本中重新定义。 - 如果希望环境变量永久生效,则可以将其放在用户环境变量文件或全局环境变量文件里。
普通变量
定义
变量名:一般是由字母、 数字 、下划线组成的,不能以数字开头
变量值:可以用单引号或双引号引起来,也可不加引号,但是这三者的含义是不同的。
把命令的结果作为变量的内容赋值
**变量名=(command)∗∗,把命令用∗∗(command)** ,把命令用**(command)∗∗,把命令用∗∗()**括起来
生产场景中把命令的结果作为变量的内容进行赋值的方法在脚本开发时很常见。
Shell 变量进阶知识
Shell 中特殊变量
Shell 位置参数变量
在 Shell 中存在一些特殊且重要的变量,例如:$0、$1,我们称之为位置参数变量。要从命令行、函数或脚本执行等处传递参数时,就需要在 Shell 脚本中使用位置参数变量。
部分位置参数变量如下:
- $0,获取当前执行的Shell 脚本的文件名,如果执行脚本包含了路径,那么就包括脚本路径。
- **n∗∗,获取当前执行的Shell脚本的∗∗第n个参数值∗∗。如果n大于9,则用大括号括起来,例如n**,获取当前执行的 Shell 脚本的**第n个参数值**。如果n大于9,则用大括号括起来,例如n∗∗,获取当前执行的Shell脚本的∗∗第n个参数值∗∗。如果n大于9,则用大括号括起来,例如{10},接的参数以空格隔开。
- $#,获取当前执行的 Shell 脚本后面接的参数数量。
- **∗∗∗,获取当前Shell脚本所有传参的参数,不加引号和‘***,获取当前 Shell 脚本所有传参的参数,不加引号和`∗∗∗,获取当前Shell脚本所有传参的参数,不加引号和‘@
相同;如果给∗‘加上双引号,例如:‘"*`加上双引号,例如:`"∗‘加上双引号,例如:‘"*",则表示将所有的参数视为单个字符串,相当于$1 $2 $3`。 - **@∗∗,获取当前Shell脚本所有传参的参数,不加引号和@**,获取当前 Shell 脚本所有传参的参数,不加引号和@∗∗,获取当前Shell脚本所有传参的参数,不加引号和*相同;如果给@加上双引号,例如:‘@加上双引号,例如:`@加上双引号,例如:‘@
,则表示将所有的参数视为不同的独立字符串,相当于"$1"、“$2”、“$3”…`,这是将多参数传递给其他程序的最佳方式,因为它会保留所有的内嵌在每个参数里的任何空白。
[root@localhost ~10:49:43]# vim showargs.sh#!/bin/bashecho$0echo$1echo$2echo$10echo${10}echo$#echo$*echo"$*"echo$@echo"$@"[root@localhost ~10:59:18]# bash showargs.sh {a..z}showargs.sh a b a0 j26a b c d e f g h i j k l m n o p q r s t uvw x y z a b c d e f g h i j k l m n o p q r s t uvw x y z a b c d e f g h i j k l m n o p q r s t uvw x y z a b c d e f g h i j k l m n o p q r s t uvw x y zShell 进程中的特殊状态变量
$?
作用:获取执行上一个指令的执行状态返回值:0为成功,非零为失败,这个变量最常用。
[root@localhost ~11:22:22]# ll[root@localhost ~11:23:04]# echo $?0Shell 内置变量命令
bash Shell 包含一些内置命令。 这些内置命令在目录列表里是看不见的,它们由 Shell 本身提供。常用的内部命令有:echo、eval、exec、read、shift等。
echo
echo命令参数选项:
- -n,不换行输出内容。
- -e,解析转义字符(见下面的字符)
转义字符:
- \n,换行。
- \t,制表符(tab)。
- \b,退格。
- \r,回到行首。
[root@localhost ~14:36:18]# echo -n "CSR";echo csrCSRcsr[root@localhost ~15:03:59]# echo -e "CSR \n csr"CSR csr[root@localhost ~15:08:09]# echo -e "CSR \ncsr"CSR csr[root@localhost ~15:16:30]# echo -e "CSR\tcsr"CSR csr[root@localhost ~15:27:50]# echo -ne "123\b";echo haha12haha[root@localhost ~15:32:09]# echo -e "CSR\rhaha"hahaeval
当 Shell 程序执行到 eval 语句时, Shell 读入参数args,并将它们组合成一个新的命令,然后执行。
[CSR@localhost ~11:00:14]$vimnoeval.sh[CSR@localhost ~11:01:20]$bashnoeval.sh hello$1[CSR@localhost ~11:02:03]$bashnoeval.sh hello world$2[CSR@localhost ~11:02:09]$vimeval.sheval"echo \$$#"[CSR@localhost ~11:10:02]$basheval.sh hello world world[CSR@localhost ~11:12:10]$basheval.sh hello haha nihao it itread
从标准输入读取字符串等信息, 传给 Shell 程序内部定义的变量。
[root@localhost ~15:40:37]# vim read.sh#!/bin/bashread-p"输入你想要说的话:"strecho"你想说的话是:$str"[root@localhost ~16:44:30]# bash read.sh输入你想要说的话:hello 你想说的话是:hello# 静默输入[root@localhost ~16:58:53]# read -s -p "请设置用户密码:" password请设置用户密码:[root@localhost ~17:09:39]# echo $password123开发脚本password,实现类似passwd工具更改密码。
[root@localhost ~17:57:03]# vim scr_password#!/bin/bashecho"更改用户$1的密码"read-sp"新的密码:"password1echoread-sp"重新输入新的密码:"password2echoecho$password1|passwd--stdin$1[root@localhost ~17:57:28]# bash ./scr_password CSR更改用户 CSR 的密码 新的密码: 重新输入新的密码: Changing passwordforuser CSR. passwd: all authentication tokens updated successfully.exec
exec 命令能够在不创建新的子进程的前提下, 转去执行指定的命令, 当指定的命令执行完毕后, 该进程 (也就是最初的 Shell ) 就终止了。
[CSR@localhost ~10:24:51]$sudo-i[root@localhost ~10:25:31]# psPID TTY TIME CMD1609pts/0 00:00:00bash1690pts/0 00:00:00su1719pts/0 00:00:00su1720pts/0 00:00:00bash1733pts/0 00:00:00ps[root@localhost ~10:25:35]# exec sleep 10You have new mailin/var/spool/mail/root# sleep命令运行完成后自动返回到原先普通用户shell了。[CSR@localhost ~10:26:38]$shift
[CSR@localhost ~11:33:21]$vimshift.sh#!/bin/bashecho$1shiftecho$1[CSR@localhost ~11:44:04]$bashshift.sh1234512变量的数值计算实践
算术运算符
如果要执行算术运算,就会离不开各种运算符号,和其他编程语言类似,Shell 也有很多算术运算符。
下面就给大家介绍一下常见的 Shell 算术运算符:
- +、-,一元正号和负号。
- +、-,加法和减法。
- *、/、%,乘法、除法、取余(取模)。
- **,幂运算。
- ++、–,增加及减少,可前置也可放在变量结尾。
- !、&&、||,逻辑非(取反)、逻辑与(and)、逻辑或(or)。
- <、<=、>、>=,比较符号(小于、小于等于、大于、大于等于)。
- ==、!=、=,比较符号(相等、不相等,对于字符串也可以表示相当于)。
- <<、>>,向左移位、向右移位。
- ~、|、&、^,按位取反、按位异或、按位与、按位。
- =、+=、-=、*=、/=、%=,赋值运算符,例如
a+=1相当于a=a+1,a-=1相当于a=a-1。
Shell 中常见的算术运算命令:
- (()),用于整数运算的常用运算符,效率很高。
- let,用于整数运算,类似于
(())。 - expr,可用于整数运算,但还有很多其他的额外功能。
- bc,Linux下的一个计算器程序(适合整数及小数运算)。
- $[],用于整数运算。
- awk,awk 既可以用于整数运算,也可以用于小数运算。
- declare,定义变量值和属性,-i参数可以用于定义整形变量,做运算。
(()) 双小括号数值运算命令
双小括号 (()) 的作用是进行数值运算与数值比较,它的效率很高,用法灵活,是企业场景运维人员经常采用的运算操作符。
5.2.1 (()) 双小括号数值运算的基础语法
双小括号 (()) 的操作方法:
- ((i=i+1)),此种书写方法为运算后赋值法,即将i+1的运算结果赋值给变量i。
注意:不能用echo ((i=i+l))输出表达式的值,可以用echo $((i=i+l))输出其值。
- **i=((i+1))∗∗,可以在‘(())‘前加‘((i+1))**,可以在 `(())` 前加 `((i+1))∗∗,可以在‘(())‘前加‘` 符,表示将表达式运算后赋值给i。
- (( 8>7 && 5==5)),可以进行比较操作,还可以加入逻辑与和逻辑或,用于条件判断。
- **echo((2+1))∗∗,需要直接输出运算表达式的运算结果时,可以在‘(())‘前加‘((2+1))**,需要直接输出运算表达式的运算结果时,可以在 `(())` 前加 `((2+1))∗∗,需要直接输出运算表达式的运算结果时,可以在‘(())‘前加‘` 符。
(()) 双小括号数运算实践
示例1
[CSR@localhost ~13:49:25]$echo$((6*3))18[CSR@localhost ~13:59:25]$a=3[CSR@localhost ~13:59:32]$b=8[CSR@localhost ~13:59:36]$echo$((a*b))24示例2
[CSR@localhost ~14:09:14]$echo$((a=2+3**2-4%3))10[CSR@localhost ~14:11:46]$a=$((100*(100+1)/2))[CSR@localhost ~14:27:44]$echo$a5050特殊运算符
# 特殊运算符[CSR@localhost ~14:35:27]$a=11;echo$((a+=1))12# 比较和判断[CSR@localhost ~14:35:50]$((1>5))[CSR@localhost ~14:36:57]$echo$?1比较和判断
# 执行 echo $((a++)) 和 echo $((a--)) 命令输出整个表达式时,输出的值即为 a 的值,表达式执行完毕后,会对a进行++、--的运算[CSR@localhost ~15:20:29]$a=10[CSR@localhost ~15:20:38]$echo$((a++))10[CSR@localhost ~15:21:23]$echo$((a++))11[CSR@localhost ~15:22:42]$echo$((a++))12# 执行 echo $((++a)) 和 echo $((--a)) 命令输出整个表达式时,会先对a进行++、--的运算,然后再输出表达式的值,即为a运算后的值。[CSR@localhost ~15:22:45]$echo$((--a))12[CSR@localhost ~15:23:23]$echo$((--a))11通过 (())运算后赋值给变量
[CSR@localhost ~15:30:07]$num=99[CSR@localhost ~15:31:00]$echonum=$((num+1))num=100let 命令
let运算命令的语法格式为:let 表达式
let表达式的功能等同于:((表达式))
[CSR@localhost ~16:58:31]$i=2[CSR@localhost ~16:58:46]$echo$((i+=2))4[CSR@localhost ~16:59:43]$leti+=8[CSR@localhost ~17:03:35]$echo$i12expr 命令
命令既可以用于整数运算,也可以用于相关字符串长度、匹配等的运算处理。
expr 命令的基本用法示例
[CSR@localhost ~17:17:06]$expr2+22+2[CSR@localhost ~17:17:14]$expr2+24[CSR@localhost ~17:17:27]$expr2\*24[CSR@localhost ~17:18:18]$expr2*22*2[CSR@localhost ~17:19:00]$expr2*2expr: syntax error在使用expr时:
- 运算符及用于计算的数字左右都至少有一个空格,否则会报错。
- 使用乘号时,必须用反斜线屏蔽其特定含义,因为 Shell 可能会误解星号的含义。
expr 的企业级实战案例详解
例1
# 计算字符串的长度[CSR@localhost ~17:51:26]$str="abc123"[CSR@localhost ~17:53:14]$exprlength"$str"6例2
# 打印下面语句中字符数不大于6 的单词[CSR@localhost ~17:54:02]$vimscr.sh#!/bin/bashstrings="This world is the script"forwordin$stringsdoif[$(exprlength"$word")-le6];thenecho$wordfidone[CSR@localhost ~18:08:09]$bashscr.sh This world is the scriptbc 命令
bc是UNIX/Linux下的计算器,因此,除了可以作为计算器来使用,还可以作为命令行计算工具使用。
[CSR@localhost ~20:43:12]$bcbc1.06.95 Copyright1991-1994,1997,1998,2000,2004,2006Free Software Foundation, Inc. This isfreesoftware with ABSOLUTELY NO WARRANTY. For detailstype`warranty'. 2^3 8 scale=4 2/3 .6666 qui [CSR@localhost ~ 20:47:04]$ echo 'scale=4;2/3'|bc.6666awk 命令实现计算
适合小数和整数,特别是命令行计算,尤其是小数,运算很精确,好用。
[CSR@localhost ~21:22:02]$echo3.58.8|awk'{ print $1-$2 }'-5.3Shell 脚本的条件测试
条件测试方法综述
执行条件判断表达式后通常会返回"真"或"假",就像执行命令后的返回值为0,表示真;非0,表示假。
在 bash 编程里,条件测试常用的语法如下:
- 语法1:test <判断表达式>,test命令和"<判断表达式>"之间至少有一个空格。
- 语法2:[ <判断表达式> ],和test命令的用法相同,这是推荐方法。
[]的边界和内容之间至少有一个空格。 - 语法3:[[ <判断表达式> ]],是比test和[]更新的语法格式。
[[]]的边界和内容之间至少有一个空格。 - 语法4:(( <判断表达式> )),一般用于 if 语句。
(())(双小括号)两端不需要有空格。 - 语法5:comand,命令的返回值确定表达式的真值或假值。
有几个注意事项需要说明一下:
- 语法1中的
test命令和语法2中的[]是等价的,语法3中的[[]]为扩展的test命令,语法4中的(())常用于计算。建议使用相对友好的语法2,即中括号[]的语法格式。 - 在
[[ ]](双中括号)中可以使用通配符等进行模式匹配,这是其区别于其他几种语法格式的地方。 &&、||、>、<等操作符可以应用于[[]]中,但不能应用于[]中,在[]中一般用-a、-o、-gt(用于整数)、-lt(用于整数)代替上述操作符。- 对于整数的关系运算,也可以使用 Shell 的算术运算符
(())。
test 条件测试的简单语法及示例
test条件测试的语法格式为:test <判断表达式>
# 判断文件是否存在[root@localhost ~17:30:37]# test -f script && echo "文件存在" || echo "文件不存在"文件存在该语句表示如果file文件存在,则输出true,否则输出false。这里的&&是逻辑与,||是逻辑或。test的-f参数用于测试文件是否为普通文件,test命令若执行成功(为真),则执行&&后面的命令,而||后面的命令是test命令执行失败之后(为假)所执行的命令。
另外,逻辑操作符&&和||的两端既可以有空格,也可以无空格。带空格看起来会更美观一些,建议使用带空格的格式。
[](中括号)条件测试语法及示例
[]条件测试的语法格式为:[ < 判断表达式> ]
⚠️ 中括号内部的两端要有空格,[]和test等价,即test的所有判断选项都可以直接在[]里使用。
# 判断文件是否存在[root@localhost ~18:25:15]# [ -f script ] && echo "文件存在" || echo "文件不存在"文件存在[[]](双中括号)条件测试语法及示例
[[]]条件测试的语法格式为:[[ < 判断表达式> ]]
⚠️双中括号里的两端也要有空格。
# 判断文件是否存在[root@localhost ~18:25:58]# [[ -f script ]] && echo "文件存在" || echo "文件不存在"文件存在[]、[[]]、(())的用法小结:
- 整数加双引号的比较是对的。
[[]]中用类似-eq等的写法是对的,[[]]中用类似>、<的写法也可能不对,有可能会只比较第一位,逻辑结果不对。[]中用类似>、<的写法在语法上虽然可能没错,但逻辑结果不对,可以使用=、!=正确比较。(())中不能使用类似-eq等的写法,可以使用类似>、<的写法。
文件判断表达式
文件测试常用选项:
- -d 文件,d的全拼为directory文件存在且为目录则为真,即判断表达式成立。
- -f 文件,f的全拼为file文件存在且为普通文件则为真,即判断表达式成立。
- -e 文件,e的全拼为exist文件存在则为真,即判断表达式成立。区别于"-f",-e不辨别是目录还是文件。
- -r 文件,r的全拼为read文件存在且可读则为真,即判断表达式成立。
- -s 文件,s的全拼为size文件存在且文件size不为0则为真,即判断表达式成立。
- -w 文件,w的全拼为write文件存在且可写则为真,即判断表达式成立。
- -x 文件,x的全拼为executable文件存在且可执行则为真,即判断表达式成立。
- -L 文件,L的全拼为link文件存在且为链接文件则为真,即判断表达式成立。
- f1 -nt f2,nt的全拼为newer than,文件fl比文件f2新则为真,即判断表达式成立。根据文件的修改时间来计算。
- f1 -ot f2,ot的全拼为older than,文件fl比文件f2旧则为真,即判断表达式成立。根据文件的修改时间来计算。
字符串判断表达式
字符串测试操作符的作用包括:比较两个字符串是否相同、测试字符串的长度是否为零、字符串是否为NULL等。
常用字符串测试操作符:
- -n “字符串”,若字符串的长度不为0,则为真,即判断表达式成立,n可以理解为no zero。
- -z “字符串”,若字符串的长度为0,则为真,即判断表达式成立,z可以理解为zero的缩写。
- “串1” = “串2”,若字符串1等于字符串2,则为真,即判断表达式成立,可使用"==“代替”="。
- “串1” != “串2”,若字符串1不等于字符串2,则为真,即判断表达式成立,但不能用"!==“代替”!="。
以下是针对字符串测试操作符的提示:
- 对于字符串的测试,一定要将字符串加双引号之后再进行比较,如
[ -n "$myvar" ],特别是使用[]的场景。 - 比较符号(例如=和!=)的两端一定要有空格。