Shell 脚本学习

Shell 脚本学习

1、条件测试

在编写shell脚本的时候,有时需要先测试 字符串是否相等数值是否相等检查文件状态,基于这些结果再进行下一步操作。条件测试可以用于测试字符串、数值、文件状态。

数值测试

数值测试用于对两个数值进行比较,并得出判断结果。 包括:大于、小于、等于、大于等于、小于等于、不等于。

数值判断的格式: [ 数值1 关系运算符 数值2 ]

注意: 方括号与条件之间必须要有空格。

数值测试关系运算符

关系运算符说明
-eq两个数值相等
-ne两个数值不相等
-gt第一个数大于第二个数
-lt第一个数小于第二个数
-ge第一个数大于等于第二个数
-le第一个数小于等于第二个数

字符串测试

字符串测试可以对两个字符串的值进行比较,也可以测试单个字符串的值是否为空或者非空。

字符串测试的格式:[ 关系运算符 字符串 ] 或者 [ 字符串1 关系运算符 字符串2 ]

字符串测试关系运算符

关系运算符说明
=两个字符串相等
!=两个字符串不相等
-z字符串为空
-n字符串不为空

文件状态测试

Linux中的Shell脚本还支持文件状态的检测,包括 检测文件的类型、文件的权限、文件的长度等。

文件状态测试的格式: [ 关系运算符 字符串]

文件状态测试的关系运算符

关系运算符说明
-d目录
-f一般文件
-L链接文件
-r可读
-w可写
-x可执行
-u设置了suid
-s文件长度大于0、非空

条件测试的逻辑运算符

逻辑操作运算符分为以下3种:

  • -a 逻辑与
  • -o 逻辑或
  • ! 逻辑非

2、控制结构

if - then - else 分支结构

if - then -else 是一种基于条件测试结果的流程控制结构,如果条件测试结果为真,则执行控制结构中相应的命令列表,否则将进入另外一个条件测试或者退出该控制结构。

if - then - else 语法格式:

if 条件1
	then 命令列表1
elif 条件2
	then 命令列表2
else 命令列表3
fi

注意: 假如之下执行了命令列表1 就会直接跳出该控制结构, 没有执行就进入下一个条件测试语句。不会执行多个命令列表,执行完一个命令列表后就会跳出该控制结构。

case 分支结构

if - then - else 可以提供多路分支(多个elif) ,但是如果分支过多,程序就会变得难以阅读。case 分支结构提供了一种实现多路分支更简洁的方法。

case 语法:

case 值或变量 in 
模式1)
	命令列表1
	;;
模式2)
	命令列表2
	;;
...
esac

for 循环结构

​ for 循环结构可以重复执行一个命令列表,基于for 语句中的 值列表 决定是继续循环还是跳出循环、for 循环在执行命令列表前会检查值列表中是否还有未被使用的值,如果有的话,则把该值赋值给for语句中指定的变量,然后执行循环结构中的命令列表。如此循环,直到值列表中所有的值被使用。

for 循环结构语法:

for 变量名 in 值列表
do 
	命令1
	命令2
	命令3
	...
done

在for 循环中的 值列表有三种类型: 常量作为值列表、变量作为值列表、命令运行结果作为值列表

  • 常量作为值列表

    #!/bin/bash
    for n in 1 2 3 4 5 6 		#循环读取 1 - 6
    do
    	echo $n
    done
    
    #运行结果: 
    1
    2
    3
    4
    5
    6
    
    
  • 以变量作为值列表 (值列表可以是一个环境变量)

#!/bin/bash
values="1 2 3 4 5 6"
for n in $values
do 
	echo $n
done

#运行结果: 
1
2
3
4
5
6
  • 以命令行结果作为值列表

    #!/bin/bash
    for n in `ls`         #循环读取 ls 命令的输出结果
    do
           echo $n        #输出变量 n 的值
    done
    
    #运行结果:
    case.sh
    for1.sh
    for2.sh
    for3.sh
    HelloWorld.sh
    number1.sh
    number.sh
    test1
    test2
    test.sh
    

expr 命令计算器

​ expr 是一个命令行的计算器,用于加、减、乘、除运算。

[root@localhost 20190105]# expr 123 + 456 - 78  //123 加 456 减 78 等于 501
501
[root@localhost 20190105]# expr 9 \* 8       //9 乘以 8 等于 72
72
[root@localhost 20190105]# expr 666 / 8      // 666 除以 8 等于 83
83

在循环结构中,expr 会被用作增量计算,初始值为10,每次使用expr增加加11/12。注意:这里使用expr命令时都使用的是反撇号,不是单引号。

[root@localhost 20190105]# number=10
[root@localhost 20190105]# number=`expr $number + 11` //对number变量的值加11
[root@localhost 20190105]# echo $number
21
[root@localhost 20190105]# number=`expr $number + 12` //对number变量的值加12
[root@localhost 20190105]# echo $number
33

while 循环结构

while 循环结构的语法:

while 条件
do 
	命令1
	命令2
	...
done

  • 循环增量计算:是在while循环中使用增量计算,其运行结果如下。
#!/bin/bash
count=0			#将count变量置为0
#变量小于5时继续循环
while [ $count -lt 5 ]
do
# 每循环一次 count 加一
	count=`expr $count + 1` # 注意 + 运算符两边需要空格
	echo $count
done

#结果
[root@localhost 20190105]# sh while1.sh
1
2
3
4
5
  • 循环从文件中读取内容

    现有一文件,保存了学生的成绩信息,其中第一列是学生名,第二列是学生的成绩。

[root@localhost 20190105]# vi students.log
jake 85
tom  68
lucy 79
sam  95

现在要对以上文件中的学生成绩进行统计,计算学生的数量以及学生的平均成绩。通过 while read 语句读取变量 STUDENT 和 SCORE 的内容,然后在 while 循环中通过 expr 命令计算学生总数和学生总成绩,最后计算平均值并输出。执行该脚本时需要把 students.log 文件的内容重定向到 while2.sh脚本中。

[root@localhost 20190105]# vi while2.sh
#!/bin/bash
TOTAL=0            //将变量 TOTAL 置 0
COUNT=0            //将变量 COUNT 置 0
#循环读取数据
while read STUDENT SCORE
do
#计算总成绩
       TOTAL=`expr $TOTAL + $SCORE`
#计算学生数
       COUNT=`expr $COUNT + 1`
done
#计算平均成绩
AVG=`expr $TOTAL / $COUNT`
echo 'There are '$COUNT' students , the avg score is '$AVG
[root@localhost 20190105]# sh while2.sh < students.log
There are 4 students , the avg score is 81
[root@localhost 20190105]#

相关知识:

在shell中

‘>’ 为创建: echo “hello shell” > out.txt

‘>>’ 为追加:echo “hello shell” >> out.txt

当out.txt 文本不存在时,'>'与‘>>’都会默认创建out.txt文本,并将hello shell 字符串保存到out.txt中。

当out.txt文本存在时,‘>’会将out.txt文本中的内容清空,并将hello shell 字符串存入。

而‘>>’会将 hello shell追加保存到out.txt的末尾。

关于Shell 中 read的用法:

https://blog.csdn.net/appke846/article/details/80420242?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162865075516780357271667%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=162865075516780357271667&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_click~default-1-80420242.pc_search_result_control_group&utm_term=shell+read&spm=1018.2226.3001.4187

until 循环结构

until是除 for 和 while以外的一种循环结构,它会循环执行一系列命令直到条件为真时停止

until循环结构语法:

until 条件
do
 命令1
 命令2
 ...
done

3、脚本参数与交互及常见问题

在执行脚本程序的时候,会经常需要向脚本传递一些参数,并根据输入的参数值生成相应的数据,或者执行相应的特定逻辑。

1.向脚本传递参数

在执行Shell脚本的时候可以带参数,在Shell脚本中有变量与之对应进行引用。这类变量的名字很特别,分别是0、1、2、3、… 被称为位置变量

位置变量从 0 开始,其中 0 变量被预留用来保存实际脚本的名字,1 变量对应脚本程序的第一个参数,以此类推。和其他变量一样,可以在Shell中通过用 “$” 符号引用位置变量的值。

#!/bin/bash
#显示脚本名
echo 'The script name is '$0
#显示第1个参数
echo 'The 1th parameter is '$1
#显示第2个参数
echo 'The 2th parameter is '$2
#显示第3个参数
echo 'The 3th parameter is '$3
#显示第4个参数
echo 'The 4th parameter is '$4
#显示第5个参数
echo 'The 5th parameter is '$5
#显示第6个参数
echo 'The 6th parameter is '$6
#显示第7个参数
echo 'The 7th parameter is '$7
#显示第8个参数
echo 'The 8th parameter is '$8
#显示第9个参数
echo 'The 9th parameter is '$9

2.用户的交互

使用 read 命令可以从键盘上读取数据,然后赋值给指定变量。在 Shell 脚本中用来实现与用户的数据交互。

read 命令格式:

read 变量1 [ 变量2 ... ]

read 命令可以从键盘上读取多个变量的值,用户输入数据时,数据间用空格或者 Tab 按键隔开。

如果变量的个数与输入的数据个数相等,则一次对应赋值。

如果变量的个数大于输入的数据个数,从左到右对应赋值;如果没有数据,则与之对应的变量为空。

如果变量的个数小于输入的数据个数,从左到右对应赋值;最后一个变量被赋予剩下的所有数据。

例子: 通过 read 命令读取键盘的输入数据保存在变量中,同时把变量值显示在屏幕上,当用户输入 exit 时结束程序

#!/bin/bash
#初始化变量的值
input1=' ';
input2=' ';
input3=' ';
input4=' ';

#until 循环,当 input1 变量的值为 exit 时退出该循环
until [ "$input1" = exit ]
do 
	echo 'Please input the values:'
#读取键盘输入的数据
	read input1 input2 input3 input4
#当输入不是 exit 时将数据输出到屏幕上
	if [ "$input1" != exit ]
	then 
		echo 'input1: '$input1
		echo 'input2: '$input2
		echo 'input3: '$input3
		echo 'input4: '$input4
#当输入为 exit 时在屏幕上显示退出脚本的提示信息
	else
		echo 'Exit the script'
	fi
done

3.特殊变量

特殊变量及说明

变量名说明
$#传递给脚本的参数个数
$*传递给脚本的所有参数的值
$@与 $* 功能相同
$$脚本执行所对应的进程号
$!后台运行的最后一个进程的进程号
$-显示 Shell 使用的当前选项
$?显示命令的退出状态 0正确 1错误

4. Shell 编程常见问题

(1) 如何屏蔽命令的输出结果

Linux 会默认创建一个设备文件 /dev/null(空设备),所有输出到该设备的信息都会被屏蔽。

通过把命令的输出重定向到设备 /dev/null ,可以屏蔽命令的输出结果。

命令 > /dev/null

屏蔽命令的错误输出

命令 2> /dev/null

屏蔽命令的正常和错误输出

命令 > /dev/null 2> /dev/null

例如:要在 Shell 代码中使用 grep 查找文件是否存在某个关键字,但有不希望输出 grep 命令的执行结果。

if grep jack /etc/passwd > /dev/null
then
	echo "jack found"
fi

如果 /etc/passwd 文件中有 jack 关键字的信息,将会显示 jack found ,但不会显示 grep 命令的执行结果。

(2)如何将一条命令分成多行编写

Linux 中的 Shell 脚本功能十分强大,他允许用户通过管道方式把多个命令组合在一起,因此也导致在一行 Shell 脚本代码中编写的命令过长,难以阅读,为了是脚本结构更加清晰,可以把一行 Shell 代码分成多行编写。

使用两个管道符把 ps、grep、awk命令组合起来。

[root@localhost ~]# ps -ef | grep sshd | awk '{print $2}'
4478
12821
22028

在一行代码中把多个命令组合在一起,难以阅读。Shell 提供了一个特殊字符“\”,可以把一行代码分成多行进行编写。

[root@localhost ~]# ps -ef | \
> grep ssh | \
> awk '{print $2}'
4478
12821
23375

4、Shell 脚本中 ‘$’ 符号的多种用法

1. 引用变量

引用变量的时候,使用 '$'符号 直接引用,以及包括循环变量;

[root@localhost ~]# x=1024
[root@localhost ~]# echo $x
1024

利用 “ ” 括起来的字符串支持变量插值。

[root@localhost ~]# x=1024
[root@localhost ~]# echo "x = $x"
x = 1024

使用 ${} 作为单词边界。

[root@localhost ~]# x=1024
[root@localhost ~]# echo "x = ${x}xy"
x = 1024xy

使用 ${#} 获取变量字符串长度。

[root@localhost etc]# s=helloworld
[root@localhost etc]# echo "s.length = ${#s}"
s.length = 10

2.引用脚本或函数参数

基于引用脚本的方式, 0 代表脚本文件名, n 从 1 开始 表示第 n 个参数;比如第二个参数是 $2。

[root@localhost ~]# echo 'echo $1 $2 $3' > ping.sh
[root@localhost ~]# cat ping.sh
echo $1 $2 $3
[root@localhost ~]# sh ping.sh 1 2 3
1 2 3

单引号 ’ ’ 括起来的不会进行插值,并使用 $# 来获取 脚本或函数 的参数个数。

[root@localhost ~]# echo 'echo $#' > ping.sh
[root@localhost ~]# sh ping.sh 1 2 3
3

3.上条命令的返回值

使用 $? 上一条命令的返回值。0 表示没有错误,其他任何数值表示有错误。

[root@localhost ~]# true 1024
[root@localhost ~]# echo $?
0
[root@localhost ~]# false 2048
[root@localhost ~]# echo $?
1

4.执行并获取命令输出

使用 $() 执行并且获取命令输出,等于``(不是单引号)的功能。

[root@localhost ~]# echo `date`
2016年 06月 05日 星期日 12:39:08 CST
[root@localhost ~]# echo $(date)
2016年 06月 05日 星期日 12:39:34 CST

5.表达式求值

使用 [ ] 对表达式进行求值,与命令 e x p r 不同的是: [ ] 对表达式进行求值,与命令 expr 不同的是: []对表达式进行求值,与命令expr不同的是:[ ] 用于插值,则 expr 用于将值进行输出。

[root@localhost ~]# echo $[1024 + 2048]
3072
[root@localhost ~]# expr 1024 + 2048
3072
[root@localhost ~]# a=1024
[root@localhost ~]# b=2048
[root@localhost ~]# echo $[ a + b ]
3072

6.获取当前进程 ID

Shell 中可以利用 $$ 符号来获取当前进程的 ID 号。

[root@localhost ~]# echo $$
55580
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值