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中 [[ ]] 和 []