Shell是人和计算机之间交流的''翻译官'',通过Shell终端解释器,可以访问到系统内核的服务,Shell执行需要脚本解释器,以及一个编写脚本的工具,一般解释器使用/bin/bash,脚本工具使用vim。Shell跟其他编程语言一样,也支持参数和变量、流程控制、分支等特性,下面简单了解一下。
脚本解释器
通过cat /etc/shells可以查看系统提供的shell脚本解释器,通过echo $SHELL命令可以查看当前默认使用的解释器,可以看出默认情况下是用/bin/bash。
# 查看提供的
[root@node01 /home/yangchaolin/hehe]# cat /etc/shells /bin/sh /bin/bash /sbin/nologin /bin/dash /bin/tcsh /bin/csh
# 查看默认使用的 [root@node01 /home/yangchaolin/hehe]# echo $SHELL /bin/bash
第一个Shell脚本
下面写一个输出"hello world"的脚本,来完成第一个shell脚本。
# vim命令进入脚本编辑
[root@node01 /home/yangchaolin/shell]# vim shell01.sh
# 编辑完查看 [root@node01 /home/yangchaolin/shell]# cat shell01.sh # 下面代表指定执行脚本的解释器
#!/bin/bash echo "hello world"
# 下面可以直接运行,不需要可执行权限 [root@node01 /home/yangchaolin/shell]# bash shell01.sh hello world
# 这种会报权限不足 [root@node01 /home/yangchaolin/shell]# ./shell01.sh -bash: ./shell01.sh: Permission denied
# 赋予可执行权限 [root@node01 /home/yangchaolin/shell]# chmod +x shell01.sh [root@node01 /home/yangchaolin/shell]# ll total 4 -rwxr-xr-x. 1 root root 31 Oct 20 12:48 shell01.sh
# 正常执行 [root@node01 /home/yangchaolin/shell]# ./shell01.sh hello world
# 全路径名执行脚本 [root@node01 /home/yangchaolin/shell]# /bin/bash shell01.sh hello world
变量
shell中也有变量,命名只能使用字母、数字和下划线,并且首字母不能以数字开头,变量和等号之间不能有空格。
(1)创建变量并使用
# 定义变量
[root@node01 /home/yangchaolin/shell]# name=messi
# $加变量名可以获得变量,大括号非必须,但是当解释器无法识别变量边界,则需添加 [root@node01 /home/yangchaolin/shell]# echo $name messi [root@node01 /home/yangchaolin/shell]# echo ${name} messi
# 解释器无法识别变量边界,打印变量部分为空 [root@node01 /home/yangchaolin/shell]# echo "$name10 is a good football player" is a good football player
# 解释器可以识别变量边界 [root@node01 /home/yangchaolin/shell]# echo "${name}10 is a good football player" messi10 is a good football player
(2)变量可以重复赋值并覆盖,也可以删除,只读变量除外。
# 在上面测试的基础上,变量重新定义
[root@node01 /home/yangchaolin/shell]# name=herri [root@node01 /home/yangchaolin/shell]# echo ${name} herri
# 定义只读变量age [root@node01 /home/yangchaolin/shell]# readonly age=28 [root@node01 /home/yangchaolin/shell]# echo $age 28 [root@node01 /home/yangchaolin/shell]# age=22
# 无法更改年龄,果然是青春一去不复返啊 -bash: age: readonly variable
# 可以删除普通变量name [root@node01 /home/yangchaolin/shell]# unset name
# 删除完后打印结果为空 [root@node01 /home/yangchaolin/shell]# echo $name [root@node01 /home/yangchaolin/shell]# unset age
# 只读变量说明也不能删除 -bash: unset: age: cannot unset: readonly variable
字符串
(1)字符串相关操作,注意单引号和双引号的区别,单引号的内容会被当做普通字符串来处理,双引号的内容会按照原有的属性值输出。
# 定义变量属性值
[root@node01 /home/yangchaolin/shell]# name=messi
# 单引号直接打印字符串 [root@node01 /home/yangchaolin/shell]# echo '$name' $name
# 双引号才打印name原有的属性值messi [root@node01 /home/yangchaolin/shell]# echo "$name" messi
(2)字符串拼接
# 确认变量内容
[root@node01 /home/yangchaolin/shell]# echo $name messi
# 使用单引号拼接 [root@node01 /home/yangchaolin/shell]# string1='hello,'$name [root@node01 /home/yangchaolin/shell]# string2='hello,$name'
# 打印结果看出,单引号内部输出变成字符串 [root@node01 /home/yangchaolin/shell]# echo $string1;echo $string2 hello,messi hello,$name
# 双引号拼接,正常打印
[root@node01 /home/yangchaolin/shell]# string1="hello,"$name
[root@node01 /home/yangchaolin/shell]# string2="hello,$name"
[root@node01 /home/yangchaolin/shell]# echo $string1;echo $string2
hello,messi
hello,messi
(3)获取字符串长度
[root@node01 /home/yangchaolin/shell]# echo $name messi [root@node01 /home/yangchaolin/shell]# echo ${#name} 5
(4)获取子字符串,方法很多,这里列出一种示意
[root@node01 /home/yangchaolin/shell]# echo $name messi # 0代表第一位,第二个数字代表截取的长度
[root@node01 /home/yangchaolin/shell]# echo ${name:0:1} m [root@node01 /home/yangchaolin/shell]# echo ${name:0:3} mes
(5)可以使用转义字符"\"将如引号、$、\、!等变成一般字符。echo时打印添加选项-e,代表允许使用反斜杠转义。
# 将$转义
[root@node02 /home/yangchaolin]# str="you win\$$name\$! " [root@node02 /home/yangchaolin]# echo -e $str you win$messi$!
# 将\转义 [root@node02 /home/yangchaolin]# str="you win\\$name\\! " [root@node02 /home/yangchaolin]# echo -e $str you win\messi\!
# 将双引号转义 [root@node02 /home/yangchaolin]# str="you win\"$name\"! " [root@node02 /home/yangchaolin]# echo -e $str you win"messi"!
数组
定义数组注意数组元素没有用逗号分隔。
# 定义一个数组 [root@node02 /home/yangchaolin/shell]# arr=(1 2 3 4 5 6)
# 查看数组内容 [root@node02 /home/yangchaolin/shell]# echo ${arr[*]} 1 2 3 4 5 6 [root@node02 /home/yangchaolin/shell]# echo ${arr[@]} 1 2 3 4 5 6
# 可以查看单个数组元素 [root@node02 /home/yangchaolin/shell]# echo ${arr[0]} 1
# 可以修改单个数组元素 [root@node02 /home/yangchaolin/shell]# arr[5]=8848 [root@node02 /home/yangchaolin/shell]# echo ${arr[@]} 1 2 3 4 5 8848
# 查看数组元素个数,数组长度 [root@node02 /home/yangchaolin/shell]# echo ${#arr[@]} 6 [root@node02 /home/yangchaolin/shell]# echo ${#arr[*]} 6
# 获取单个元素个数,如8848长度为4 [root@node02 /home/yangchaolin/shell]# echo ${#arr[5]} 4
Shell传递参数
shell可以获取用户输入的参数,具体参考下面脚本和注释更好理解。
# 编写shell脚本
[root@node02 /home/yangchaolin/shell]# cat param01.sh #!/bin/bash echo "shell传递参数测试" echo "当前文件名:$0" echo "第一个参数:$1" echo "第二个参数:$2" echo "第三个参数:$3" echo "参数个数:$#" echo "当前脚本运行的进程ID号:$$" echo "最后的退出状态:$?" echo "以单个字符显示所有传递的脚本: $*" echo "以多个字符显示所有传递的脚本: $@" # $*是将多个获取的参数整体输出,即"$1 $2 ... $n"的方式整体输出 echo "----------\$*循环的效果----------" for str in "$*"; do echo $str done # $@是将多个获取的参数单个输出,即按照"$1","$2",...,"$n"的方式单个输出 echo "----------\$@循环的效果----------" for str in "$@"; do echo $str done # 测试脚本,传递参数 [root@node02 /home/yangchaolin/shell]# bash param01.sh 梅西 C罗 亨利 shell传递参数测试 当前文件名:param01.sh 第一个参数:梅西 第二个参数:C罗 第三个参数:亨利 参数个数:3 当前脚本运行的进程ID号:3061 最后的退出状态:0 以单个字符显示所有传递的脚本: 梅西 C罗 亨利 以多个字符显示所有传递的脚本: 梅西 C罗 亨利 ----------$*循环的效果---------- 梅西 C罗 亨利 ----------$@循环的效果---------- 梅西 C罗 亨利
运算符
Shell中也有类似其他编程语言的运算符,包括算术运算、关系运算、逻辑运算,还有字符串运算和文件测试运算。
算术运算
# 脚本内容
[root@node02 /home/yangchaolin/shell]# cat arithmetic.sh #!/bin/bash # 算术运算符 echo "算术运算符"
# 32岁的亨利就坐在那里,深情的目光望去,都是自己22岁的影子,使用32和22 a=22 b=32 echo "-----加法运算a + b-----" echo `expr $a + $b` echo "-----减法运算a - b-----" echo `expr $a - $b` echo "-----除法运算a / b-----" echo `expr $a / $b` echo "-----乘法运算a \* b-----" echo `expr $a \* $b` echo "-----取余运算a % b-----" echo `expr $a % $b` echo "-----赋值运算c = \$a-----" c=$a echo $c echo "-----相等运算\$a == \$b-----" r1= [ $a == $b ] if $r1 then echo "两者相等" fi echo "-----不相等运算\$a != \$b-----" r2= [ $a != $b ] if $r2 then echo "两者不相同" fi # 运行shell脚本 [root@node02 /home/yangchaolin/shell]# bash arithmetic.sh 算术运算符 -----加法运算a + b----- 54 -----减法运算a - b----- -10 -----除法运算a / b----- 0 -----乘法运算a \* b----- 704 -----取余运算a % b----- 22 -----赋值运算c = $a----- 22 -----相等运算$a == $b----- 两者相等 -----不相等运算$a != $b----- 两者不相同 [root@node02 /home/yangchaolin/shell]#
关系运算
关系运算支持数字和内容为数字的字符串。
关系运算脚本
[root@node02 /home/yangchaolin/shell]# cat compare.sh #!/bin/bash # 关系运算符 a=32 b=22 echo "a=32,b=22" echo "-eq相等" if [ $a -eq $b ] then echo "a等于b" else echo "a不等于b" fi echo "-gt大于" if [ $a -gt $b ] then echo "a大于b" else echo "a不大于b" fi echo "-lt小于" if [ $a -lt $b ] then echo "a小于b" else echo "a不小于b" fi echo "-ge大于等于" if [ $a -ge $b ] then echo "a大于等于b" else echo "a不大于等于b" fi echo "-le小于等于" if [ $a -le $b ] then echo "a小于等于b" else echo "a不小于等于b" fi echo "-ne不等于" if [ $a -ne $b ] then echo "a不等于b" else echo "a不等于b的其他可能" fi # 执行脚本,查看效果 [root@node02 /home/yangchaolin/shell]# bash compare.sh a=32,b=22 -eq相等 a不等于b -gt大于 a大于b -lt小于 a不小于b -ge大于等于 a大于等于b -le小于等于 a不小于等于b -ne不等于 a不等于b
逻辑运算
在Shell也有短路与和短路或,但是最好用[[ ]]来配合使用。
# 查看脚本
[root@node02 /home/yangchaolin/shell]# cat compare1.sh #!/bin/bash # shell中的&&和|| echo "shell中的&&和||" a=32 b=22 echo "a=32,b=22" echo "&&逻辑AND" if [[ $a -gt 20 && $b -lt 30 && $a -ne 20 ]] then echo "返回true" else echo "返回false" fi echo "||逻辑OR" if [[ $a -gt 20 || $b -lt 10 ]] then echo "返回true" else echo "返回false" fi
# 执行脚本 [root@node02 /home/yangchaolin/shell]# bash compare1.sh shell中的&&和|| a=32,b=22 &&逻辑AND 返回true ||逻辑OR 返回true
字符串运算
注意字符串运算符使用=和!=来判断字符串是否相等或不相等。
# 查看脚本
[root@node02 /home/yangchaolin/shell]# cat character.sh #!/bin/bash # 字符串运算符 echo "shell中字符串运算符" str1="messi" str2="herry" echo "str1为messi,str2为herry" echo "=判断字符串是否相等" if [ $str1 = $str2 ] then echo "str1等于str2" else echo "str1不等于str2" fi echo "!=判断字符串是否不相等" if [ $str1 != $str2 ] then echo "str1不等于str2" else echo "str1不等于str2的其他可能" fi echo "-z判断字符串长度是否为0" if [ -z $str1 ] then echo "str1字符串长度为0" else echo "str1字符串长度不为0" fi echo "-n判断字符串长度不为0" if [ -n $str1 ] then echo "str1字符串长度不为0" else echo "str1字符串长度为0" fi echo "$判断字符串是否为空" if [ $str1 ] then echo "str1字符串不为空" else echo "str1字符串为空" fi # 执行脚本 [root@node02 /home/yangchaolin/shell]# bash character.sh shell中字符串运算符 str1为messi,str2为herry =判断字符串是否相等 str1不等于str2 !=判断字符串是否不相等 str1不等于str2 -z判断字符串长度是否为0 str1字符串长度不为0 -n判断字符串长度不为0 str1字符串长度不为0 $判断字符串是否为空 str1字符串不为空
文件测试运算
文件测试运算是Shell下比较特殊的,因为shell脚本里本质上就是一堆的命令,因此少不了文件测试运算了。
# 查看脚本
[root@node02 /home/yangchaolin/shell]# cat directory.sh #!/bin/bash #使用shell文件测试运算符 echo "shell文件测试运算符" path="/etc/sysconfig/network-scripts" file="/etc/sysconfig/network-scripts/ifcfg-eth0" echo "测试目录名为$path" echo "测试文件名为$file" echo "-d检测文件是否是目录" if [ -d $path ] then echo "是一个目录" else echo "不是一个目录" fi echo "-f检查是否是普通文件" if [ -f $file ] then echo "是一个普通文件" else echo "不是一个普通文件" fi echo "-r检查文件是否可读" if [ -r $file ] then echo "文件可读" else echo "文件不可读" fi echo "-w检查文件是否可写" if [ -w $file ] then echo "文件可写" else echo "文件不可写" fi echo "-x检查文件是否可执行" if [ -x $file ] then echo "文件可执行" else echo "文件不可以执行" fi echo "-e检查文件或目录是否存在" if [ -e $file ] then echo "文件存在" else echo "文件不存在" fi # 执行脚本 [root@node02 /home/yangchaolin/shell]# bash directory.sh shell文件测试运算符 测试目录名为/etc/sysconfig/network-scripts 测试文件名为/etc/sysconfig/network-scripts/ifcfg-eth0 -d检测文件是否是目录 是一个目录 -f检查是否是普通文件 是一个普通文件 -r检查文件是否可读 文件可读 -w检查文件是否可写 文件可写 -x检查文件是否可执行 文件不可以执行 -e检查文件或目录是否存在 文件存在
test判断
除了使用[ ],[[ ]]来进行判断外,还可以使用test,但是test只能用于数值运算,字符运算和文件测试运算。
# 脚本内容
[root@node02 /home/yangchaolin/shell]# cat testdemo.sh #!/bin/bash # 使用test进行判断 echo "使用test进行判断" echo "用于算术运算" a=$1 b=$2 echo "a=$1,b=$2" if test $a -ne $b then echo "a和b不相等" else echo "a和b不相等的其他情况" fi echo "用于字符运算符" str1=$3 str2=$4 echo "str1为$str1,str2为$str2" if test $str1 = $str2 then echo "字符串一样" else echo "字符串不一样" fi echo "用于文件测试" path="/etc/sysconfig/network-scripts" if test -d $path then echo "$path是目录" else echo "$path不是目录" fi # 测试结果 [root@node02 /home/yangchaolin/shell]# bash testdemo.sh 10 20 messi herry 使用test进行判断 用于算术运算 a=10,b=20 a和b不相等 用于字符运算符 str1为messi,str2为herry 字符串不一样 用于文件测试 /etc/sysconfig/network-scripts是目录
另外test中,还可以使用与-a、或-o和非!,将逻辑操作符进行组合,优先级是!>-a>-o
[root@node02 /home/yangchaolin/shell]# cat testdemo01.sh #!/bin/bash # test的与或非测试 echo "test的与-a或-o非!" if test -e /root -o /home/messi then echo "至少有一个目录或文件存在" else echo "两个都不存在" fi [root@node02 /home/yangchaolin/shell]# bash testdemo01.sh test的与-a或-o非! 至少有一个目录或文件存在
if相关
Shell中支持if条件判断,可以使用if、if-else和else-if。上面已经用了大量的if相关的脚本,下面再练习下。
# 查看脚本,这里使用test
[root@node02 /home/yangchaolin/shell]# cat ifcase.sh #!/bin/bash # if相关测试 echo "if相关的测试" echo "-----if测试-----" if test $1 -gt $2 then echo "$1大于$2" fi echo "-----if-else测试-----" if test $1 -ge $2 then echo "$1大于等于$2" else echo "$1小于$2" fi echo "-----elif测试-----" if test $1 -eq $2 then echo "$1等于$2" elif test $1 -gt $2 then echo "$1大于$2" elif test $1 -lt $2 then echo "$1小于$2" else echo "我也不知道了" fi
#测试结果 [root@node02 /home/yangchaolin/shell]# bash ifcase.sh 32 22 if相关的测试 -----if测试----- 32大于22 -----if-else测试----- 32大于等于22 -----elif测试----- 32大于22
循环语句
Shell中也支持循环,有for循环、while循环、until循环,也可以使用break关键字退出循环。
for循环
如下使用for循环,循环打印数组内容和字符串内容,此外还可以在for循环中使用break。
# for循环脚本
[root@node02 /home/yangchaolin/shell]# cat forcase.sh #!/bin/bash # 测试循环语句 echo "for循环语句" var=(1 2 3 4 5) for i in ${var[*]} do echo "值为:$i" done echo "for顺序输出字符串的字符" i=0 string="messi is a genius in football" for str in $string do echo "$str" echo "$i" i=`expr $i + 1 ` done echo "for循环中使用break命令" i=0 string="a b c d e f g h i j k l m n o p q r s t u v w x y z" for char in $string do echo "$char" i=`expr $i + 1 ` # 判断 if test $i -eq 7 then break fi done # 执行脚本 [root@node02 /home/yangchaolin/shell]# bash forcase.sh for循环语句 值为:1 值为:2 值为:3 值为:4 值为:5 for顺序输出字符串的字符 messi 0 is 1 a 2 genius 3 in 4 football 5 for循环中使用break命令 a b c d e f g [root@node02 /home/yangchaolin/shell]#
while循环
以下是对while循环的演练,可以查看while后面的条件,有比较灵活的写法。
[root@node02 /home/yangchaolin/shell]# cat whilecase.sh #!/bin/bash # while循环测试 echo "while循环" i=0
# 使用小括号 while(( $i <=5 )) do echo "$i" let "i++" done echo "for循环" i=0
# 使用test while test $i -le 5 do echo "$i" let "i++" done echo "for循环" i=0
# 使用[ ] while [ $i -le 5 ] do echo "$i" let "i++" done
# 执行脚本,三种都可以循环打印 [root@node02 /home/yangchaolin/shell]# bash whilecase.sh while循环 0 1 2 3 4 5 for循环 0 1 2 3 4 5 for循环 0 1 2 3 4 5 [root@node02 /home/yangchaolin/shell]#
while循环还可以读取键盘输入信息。
# 脚本 [root@node02 /home/yangchaolin/shell]# cat whilecase01.sh #!/bin/bash # while循环可以获取用户输入 echo "while可以获取用户输入" echo -n '输入你喜欢的球星' while read footballstar do echo "$footballstar是一个好的球员" done # 执行脚本 [root@node02 /home/yangchaolin/shell]# bash whilecase01.sh while可以获取用户输入 输入你喜欢的球星messi messi是一个好的球员 herry herry是一个好的球员 rolly rolly是一个好的球员 [root@node02 /home/yangchaolin/shell]#
unitl循环
这个循环比较奇葩,它跟while相反,当判断条件为false时才执行。
[root@node02 /home/yangchaolin/shell]# cat untilcase.sh #!/bin/bash # until循环测试 echo "until循环" i=0
# 刚开始都小于5,判断为false才执行 until test ! $i -le 5 do echo "$i" let "i++" done
# 执行脚本 [root@node02 /home/yangchaolin/shell]# bash untilcase.sh until循环 0 1 2 3 4 5 [root@node02 /home/yangchaolin/shell]#
case
case和java中的switch-case也很类似。
# 查看脚本
[root@node02 /home/yangchaolin/shell]# cat case.sh #!/bin/bash # case测试 echo "case测试" echo "请输入你喜欢的季节" read season case $season in 春天) echo "你选择了绿色" ;; 夏天) echo "你选择了海边" ;; 秋天) echo "你选择了收获" ;; 冬天) echo "你选择了雪山" ;; *) echo "你选择了洒脱" ;; esac
# 测试脚本 [root@node02 /home/yangchaolin/shell]# bash case.sh case测试 请输入你喜欢的季节 西天 你选择了洒脱 [root@node02 /home/yangchaolin/shell]# bash case.sh case测试 请输入你喜欢的季节 夏天 你选择了海边
函数
Shell中可以定义函数,然后在shell脚本中调用。
# 脚本
[root@node02 /home/yangchaolin/shell]# cat function.sh #!/bin/bash # shell中函数的使用 echo "函数的使用" # 定义一个函数,用于打开网络配置 hello(){ echo "开始打开网卡配置文件" cd /etc/sysconfig/network-scripts && cat ifcfg-eth0 } # 函数调用 hello
# 脚本调用 [root@node02 /home/yangchaolin/shell]# bash function.sh 函数的使用 开始打开网卡配置文件 DEVICE=eth0 HWADDR=00:0c:29:27:3e:72 TYPE=Ethernet UUID=2d4241a0-fad8-45d5-86be-27f4095500ec ONBOOT=yes NM_CONTROLLED=yes BOOTPROTO=none IPADDR=192.168.145.129 NETMASK=255.255.255.0 DNS2=8.8.8.8 GATEWAY=192.168.145.2 DNS1=114.114.114.114 IPV6INIT=no USERCTL=no [root@node02 /home/yangchaolin/shell]#
函数中也可以定义返回值。
# 脚本查看
[root@node02 /home/yangchaolin/shell]# cat function01.sh #!/bin/bash echo "函数返回值测试" plus(){ echo "请输入第一个数字" read num1 echo "请输入第二个数字" read num2 echo "num1为$num1,num2为$num2" #相加 ? return $(( $num1 + $num2 )) } # 方法调用 plus echo "输入两个数和为:$?"
# 执行脚本 [root@node02 /home/yangchaolin/shell]# bash function01.sh 函数返回值测试 请输入第一个数字 10 请输入第二个数字 20 num1为10,num2为20 输入两个数和为:30 [root@node02 /home/yangchaolin/shell]#
调用函数时也可以直接再后面添加参数,供函数调用
# 查看脚本
[root@node02 /home/yangchaolin/shell]# cat function02.sh #!/bin/bash echo "函数中可以传入参数" plus(){ a=$1 b=$2 return $(( $a + $b )) } # 调用 plus 1 2 echo "求和结果为:$?"
# 执行脚本 [root@node02 /home/yangchaolin/shell]# bash function02.sh 函数中可以传入参数 求和结果为:3
以上是对shell的初步了解,后续再补充。
参考博文:
(1)《Linux就该这么学》
(2)https://blog.csdn.net/sj349781478/article/details/82930982 linux下三剑客
(3)https://www.jianshu.com/p/508e94e4479f shell中 [[ ]] 和 []