一、概念
shell是一个命令行解释器,接受应用程序/用户命令,然后调用操作系统内核。同时也是一种编程语言。
用途:
用于自动化重复性任务,例如:定期备份、监控系统状态、自动化测试等。也可以用于自动化复杂的任务,如构建软件、编译代码等。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、变量定义规则
- 变量名称可以由字母,数字和下划线组成,不能以数字开头,环境变量名建议大写
- 等号两侧不能有空格
- 在bash中,变量默认类型都是字符串类型,无法直接进行数值运算
- 变量的值如果有空格,需要使用双引号或单引号括起来
- 可把变量提升为全局变量,可供其他shell程序使用
export 变量
[linux@localhost datas]$ D="A B C"
[linux@localhost datas]$ echo $D
A B C
4、特殊变量
$n
$n
:描述:n为数字,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前后要有空格)
常用判断条件:
两个整数间的比较:
文件权限判断:
文件类型判断:
# 判断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 | 只打印匹配的行数 |