shell脚本

52 阅读3分钟

一、概念

shell是一个命令行解释器,接受应用程序/用户命令,然后调用操作系统内核。同时也是一种编程语言。

image.png 用途: 用于自动化重复性任务,例如:定期备份、监控系统状态、自动化测试等。也可以用于自动化复杂的任务,如构建软件、编译代码等。shell脚本可以跨平台使用,因为它们基于文本,可以在不同的操作系统上运行。

执行shell脚本需要指定解析器,常见的用bash,还有ksh等。

二、脚本入门

脚本以 #!/bin/bash 开头

创建脚本
touch helloworld.sh
echo "helloword" >> helloworld.sh
cat helloword.sh
执行脚本方式一:
bash helloworld.sh

执行脚本方式二:
./helloworld.sh
如果出现:-bash: ./helloworld.sh:权限不够,就更改权限:
chmod 777 ./helloworld.sh

两种执行方式的区别:

方式1,本质是bash解析器帮你执行脚本,所以脚本本身不需要执行权限;方式2,本质是脚本自己需要执行,所以需要执行权限

三、多命令处理

在脚本hello.sh中,编写多命令:在linux家目录下创建一个bangzhang.txt并在文件中写入"I IOVE YOU"字符,内容如下,然后执行脚本

#!/bin/bash
cd /home/linux/
touch banzhang.txt
echo "I love you" >> banzhang.txt

四、shell中的变量

1、常用系统变量

$HOME $PWD $SHELL $USER

[linux@localhost datas]$ echo $HOME
/home/linux
[linux@localhost datas]$ echo $PWD
/home/linux/datas
[linux@localhost datas]$ echo $SHELL
/bin/bash
[linux@localhost datas]$ echo $USER
linux

2、自定义变量

基本语法

1、定义变量:变量=值,不能有空格 2、撤销变量: Unset 变量 3、输出变量:echo $变量 4、声明静态变量:readonly 变量,注意:不能unset

[linux@localhost datas]$ A=1
[linux@localhost datas]$ echo $A
1
[linux@localhost datas]$ unset A

3、变量定义规则

  1. 变量名称可以由字母,数字和下划线组成,不能以数字开头,环境变量名建议大写
  2. 等号两侧不能有空格
  3. 在bash中,变量默认类型都是字符串类型,无法直接进行数值运算
  4. 变量的值如果有空格,需要使用双引号或单引号括起来
  5. 可把变量提升为全局变量,可供其他shell程序使用
    export 变量
[linux@localhost datas]$ D="A B C"
[linux@localhost datas]$ echo $D
A B C

4、特殊变量

$n

$n :描述:n为数字,0代表脚本名称,10以内的参数0代表脚本名称,10以内的**参数**用1-$9表示,10以上的需要用大括号包含{10}

下面是helloworld.sh脚本内容,然后输入bash helloworld.sh x1 x2 x3,输出结果为:

helloworld.sh x1 x2 x3

#!/bin/bash
echo "$0 $1 $2 $3"

$#

$#:描述:获取所有输入参数个数,常用于循环

下面是helloworld.sh脚本内容,然后输入bash helloworld.sh x1 x2 x3,输出结果为:

helloworld.sh x1 x2 x3

3

#!/bin/bash
echo "$0 $1 $2 $3"
echo $#

$*

$* :描述:代表命令行中所有的参数,把所有参数看成一个整体

$@ :描述:代表命令行中的所有参数,不过把每个参数区分对待

[linux@localhost datas]$ bash parameter.sh test1 test2
parameter.sh test1 test2 
2
test1 test2
test1 test2

$?:描述:最后一次执行命令的状态,0:正确状态

五、运算符

1、$(运算符)) 或 $[运算符]

2、expr +,-,*,/,% 加减乘除取余,expr运算符间要有空格

# 计算2+3
[linux@localhost datas]$ expr 2 + 3
5

# 计算(2+3)*4
## 方式1
[linux@localhost datas]$ expr `expr 2 + 3` \* 4
20

## 方式2
[linux@localhost datas]$ s=$[(2+3)*4]
[linux@localhost datas]$ echo $s
20

六、条件判断

基本语法

[ condition ] (注意condition前后要有空格)

常用判断条件:

两个整数间的比较

image.png

文件权限判断:

image.png

文件类型判断:

image.png

# 判断23是否大于2
[linux@localhost datas]$ [ 23 -gt 2 ]
[linux@localhost datas]$ echo $?
0

# 判断helloworld.sh是否有写入权限
[linux@localhost datas]$ [ -w hellowrld.sh ]
[linux@localhost datas]$ echo $?
1

# 判断目录中文件是否存在
[linux@localhost datas]$ [ -e /home/linux/datas ]
[linux@localhost datas]$ echo $?
0

多条件判断:

&& (与,同真为真)

|| (或,一假即假)

1、串行执行

1⃣️ 成功执行:用 && 分隔(要执行命令的上一条命令执行成功了才会执行。)

for i in {1..5};
do echo 'h1' && echo 'h2';
done

2⃣️ 失败执行:用“||”做分隔(要执行命令的上一条命令执行失败了才会执行)

3⃣️ 成功失败都执行:用“;”做分隔(不管上一条命令的执行情况,一直按顺序执行)

2、继承执行

命令与命令间使用“|”做分隔,“|”表示管道,主要功能是把上一条命令的输出,做为下一条命令参数。

七、流程控制

1、IF判断

[linux@localhost datas]$ cat if.sh
#!/bin/bash
if [ $1 -eq 1 ]
then
	echo "班长真帅"
elif [ $1 -eq 2 ]
then
	echo "班长真丑"
fi
[linux@localhost datas]$ bash if.sh 2
班长真丑

2、case语句

[linux@localhost datas]$ cat case.sh
#!/bin/bash
case $1 in
1)
	echo "班长"
;;
2)
	echo "学习委员"
;;
3)
	echo "体育委员"
;;
esac
[linux@localhost datas]$ bash case.sh 2
学习委员

3、for循环

方法1:for ((i=1; i<=100; i++))

[linux@localhost datas]$ cat for.sh
#!/bin/bash
s=0
for((i=1;i<=100;i++))
do
	s=$[$s+$i]	
done
echo $s
[linux@localhost datas]$ bash for.sh
5050

for ((i=1; i<=100; i++))
do
    echo $i
done

e.g:

for ((i=1; i<=100; i++)); 
do  
  curl -d '{"id":"123456","filename":"111.zip"}' http://127.0.0.1:9090/ss/dd/ff/sss; 

方法2:for i in {1..100}

[linux@localhost datas]$ cat for2.sh
#!/bin/bash
for i in $*
do
	echo $i
done
[linux@localhost datas]$ bash for2.sh 1 2
1
2

for i in {1..100}
do
    echo $i
done

e.g:

for i in {1..30}; 
do curl 'http://www.a.com/' -H "X-Real-IP:1.1.1.1" && curl 'http://www.a.com/1' -H "X-Real-IP:1.1.1.2" ;

done

4、while循环

[linux@localhost datas]$ cat while.sh
#!/bin/bash
s=0
i=1
while [ $i -le 100 ]
do
	s=$[$s + $i]
	i=$[$i + 1]
done
echo $s

[linux@localhost datas]$ bash while.sh
5050

八、read读取控制台输入

read(选项)(参数)

-p :指定读取值时的提示符

-t :指定读取值时等待的时间(秒)

# 提示7秒内,读取控制台输入的名称
[linux@localhost datas]$ cat read.sh
#!/bin/bash
read -t 7 -p "在7s内请输入你的名字" NAME
echo $NAME
[linux@localhost datas]$ bash read.sh
在7s

九、函数

1、系统函数

basename

basename [string / pathname] [suffix] (描述:basename命令会删掉所有的前缀包括最后一个‘/’字符,然后将字符串显示出来)

# 方式1
[linux@localhost datas]$ basename /home/linux/banzhang.txt
banzhang.txt

# 方式2
[linux@localhost datas]$ basename /home/linux/banzhang.txt .txt
banzhang

dirname

dirname 文件绝对路径 (描述:从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录的部分))

[linux@localhost datas]$ dirname /home/linux/banzhang.txt
/home/linux

2、自定义函数

# 格式
[ function ] funname[()]
{
	Action:
	[return int;]
}
funname

# DESC 计算输入两个参数的值
[linux@localhost datas]$ cat sum.sh
#!/bin/bash
function sum(){
	s=0;
	s=$[$1 + $2]
	echo $s
}
read -p "input your param1:" P1
read -p "input your param2:" P2
sum $P1 $P2
[linux@localhost datas]$ bash sum.sh
input your param1:1
input your param2:2
3

十、shell工具

1、cut

cut命令从文件的每一行剪切字节,字符和字段,并将他们进行输出

cut [选项参数] filename

  • -f 列号,提取第几行
  • -d 分隔符,按照指定分隔符分隔列
# DESC 切割cut.txt第一列
[linux@localhost datas]$ cat cut.txt
dong shen
guan zhen
wo wo
lai lai
le le
[linux@localhost datas]$ cut -d " " -f 1 cut.txt
dong
guan
wo
lai
le
cut
# DESC 获取第三行第一个单词
[linux@localhost datas]$ cat cut.txt | grep guan | cut -d " " -f 1
guan

2、sed

sed是一种流编辑器,它一次处理一行内容,处理时,把当前处理的行存储在临时缓冲区,成为“模式空间”,接着sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕,接着处理下一行,这样不断重复,直到文件末尾,文件的内容并没有改变(除非使用重定向存储输出)

sed [选项参数] ‘command’ filename

  • -e 直接在指令模式上进行sed的动作编辑

命令功能描述

  • a 新增
  • d 删除
  • s 查找并替换
# DESC 在第二行后增加mei nv字符
[linux@localhost datas]$ sed -e "2a mei nv" sed.txt
dong zhen
guan zhen
mei nv
wo wo
lai lai
#删除sed.txt文件中所有包含wo的行
[linux@localhost datas]$ sed '/wo/d' sed.txt
dong zhen
guan zhen
mei nv

lai lai
# 将 sed.txt 文件中lai替换为le,'g'代表global,全部替换
[linux@localhost datas]$ sed 's/wo/ni/g' sed.txt
dong zhen
guan zhen
mei nv

le le

3、awk

awk是一个强大的文件分析工具,把文件逐行的读入,以空格为默认分隔符将每行进行切片,切开的部分再进行处理。

awk [选项参数] ‘pattern1{action1} pattern2{aciton2}... ’ filename

选项参数:

  • -F 指定输入文件的分隔符
  • -v 赋值一个用户定义变量

pattern:表示awk在数据中查找的内容(=匹配模式)

action:找到匹配内容时的一系列命令

正则表达式:

符号含义
^表示开头,匹配输入字符串开始的位置
$表示结尾,匹配输入字符串结尾的位置
\将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如,“n”匹配字符“n”。“\n”匹配换行符。序列“\\\\”匹配“\”,"\("匹配“(”
*零次或多次匹配前面的字符或子表达式。例如,zo* 匹配“z”和“zoo”。* 等效于{0,}
+一次或多次匹配前面的字符或子表达式。例如,zo+ 匹配“zo”和“zoo”。* 等效于{1,}
[linux@localhost datas]$ cat passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

# 1、搜索passwd文件以root关键字开头的所有行,并输出该行的第7列

[linux@localhost datas]$ awk -F : '/^root/{print $7}' passwd
/bin/bash

# 2、搜索passwd文件以root关键字开头的所有行,并输出该行的第1列和第7列,中间以“,”号分隔
# (只有匹配了pattern的行才会执行action)

[linux@localhost datas]$ awk -F : '/^root/{print $1","$7}' passwd
root,/bin/bash

# 3、只显示/etc/passwd的第一列和第七列,以逗号分隔,且在所有行前面添加列名user,shell  在最后一行添加“yujin,/bin/good”
# (BEGIN在所有数据读取行之前执行;END在所有数据执行之后执行)

[linux@localhost datas]$ awdk -F : 'BEGIN{print "user,shell"} {print $1","$7} END{print "yujin,/bin/good"}' passwd
user,shell
root,/bin/bash
bin,/sbin/nologin
....
yujin,/bin/good

# 4、将passwd文件中的用户id(第3列)增加数值1并输出

[linux@localhost datas]$ awk -F : -v i=1 '{print $3+i}' passwd
1
2
3

awk的内置变量:

变量说明
FILENAME文件名
NR已读的记录数(行数,从1开始到最后一行)
NF浏览记录的域的个数(切割后,列的个数)
#1、统计passwd文件名,每行的行号,每行的列数
[linux@localhost datas]$ awk -F : '{print FILENAME "," NR "," NF}' passwd
passwd,1,7
passwd,2,7
passwd,3,7
....

# 2、切割IP
[linux@localhost datas]$ ifconfig eth0 | grep "inet addr"
    inet addr:192.168.1.101 Bcast:192.168.1.255 Mask:255.255.255.0
[linux@localhost datas]$ ifconfig eth0 | grep "inet addr" | awk -F : '{print $2}' | awk -F " " '{print $1}'
192.168.1.101

# 3、查询sed.txt中空行所在的行号
[linux@localhost datas]$ cat sed.txt
dong shen
guan zhen
lai lai

le le
[linux@localhost datas]$ awk '/^$/ {print NR}' sed.txt
4

4、sort

sort命令是在Linux里非常有用,它将文件进行排序,并将排序结果标准输出

基本语法 sort (选项)(参数)

选项说明
-n依照数值的大小排序
-r以相反的顺序来排序
-t设置排序时所用的分隔字符
-k指定需要排序的列

参数:指定待排序的文件列表

#给文件列表排序
[linux@localhost datas]$ touch sort.sh
bb:40:5.4
bd:20:4.2
xz:50:2.3
cls:10:3.5
ss:30:1.6
[linux@localhost datas]$ sort -t : -nrk 2 sort.sh
xz:50:2.3
bb:40:5.4
ss:30:1.6
bd:20:4.2
cls:10:3.5

十一、实操

1、使用Linux命令查询file1中空行所在的行号

[linux@localhost datas]$ awk '/^$/ {print NR}' file1
5

2、有文件chengji.txt内容如下:

张三 40

李四 50

王五 60

使用Linux命令计算第二列的和并输出

[linux@localhost datas]$ cat chengji.txt | awk -F " " '{sum+=$2} END {print sum}'
150

3、shell脚本里如何检查一个文件是否存在?如果不存在该如何处理?

使用到文件操作符-e-f

第一个-e用来检查文件是否存在,而不管文件类型。

第二个-f仅仅用来检查文件是常规文件(不是目录或设备)时返回true。

#!/bin/bash

if [ -f file.txt ];then
    echo "文件存在!"
else
    echo "文件不存在!"
fi

4、用shell写一个脚本,对文本中无序的一列数字排序,并计算它的和

[linux@localhost datas]$ cat test.txt
1
4
3
2
5
[linux@localhost datas]$ sort -n test.txt | awk '{a+$0;print $0} END{print "sum="a}'
1
2
3
4
5
sum=15

5、请用shell脚本写出查找当前文件夹(/home)下所有的文本文件内容中包含有字符“shen”的文件名称

[linux@localhost datas]$ grep -r "shen" /home 
/home/datas/sed.txt:dong shen
/home/datas/cut.txt:ding shen
[linux@localhost datas]$ grep -r "shen" /home | cut -d ":" -f 1
/home/datas/sed.txt
/home/datas/cut.txt

grep 命令

(global regular expression)用于查找文件里符合条件的字符串或正则表达式。

语法:

grep [options] pattern [files]

grep [-abcEFGhHilLnqrsvVwxy][-A<显示行数>][-B<显示列数>][-C<显示列数>][-d<进行动作>][-e<范本样式>][-f<范本文件>][--help][范本样式][文件或目录...]

选项
-i忽略大小写进行匹配
-v反向查找,只打印不匹配的行
-n显示匹配行的行号
-r递归查找子目录中的文件
-l只打印匹配的文件名
-c只打印匹配的行数