目录
一、概述
二、shell脚本基础概念和语法
三、表达式
四、shell脚本编写
(一)Shell脚本介绍
Shell脚本是一种用于自动化执行命令和任务的脚本语言。它是在操作系统的命令行界面下运行的,通过编写一系列的命令和逻辑来完成特定的任务。Shell脚本可以用于各种操作系统,如Linux、Unix和Mac OS等。
Shell脚本是一种强大的工具,它可以帮助用户简化重复性的任务,提高工作效率。通过编写Shell脚本,用户可以将一系列的命令和操作组合在一起,形成一个可执行的脚本文件。这样,用户只需要运行这个脚本文件,就能够自动执行其中的命令,完成特定的任务。
Shell脚本的语法相对简单,主要由一系列的命令和控制结构组成。用户可以使用各种命令来完成不同的操作,如文件操作、文本处理、系统管理等。同时,Shell脚本还支持条件判断、循环和函数等控制结构,使得用户能够编写更加复杂和灵活的脚本。
(二)Shell脚本的作用
Shell脚本的作用是通过编写一系列的命令和脚本语句,来实现自动化的任务处理和系统管理。Shell脚本可以用于执行各种操作系统命令、管理文件和目录、处理文本数据、调用其他程序等。通过编写Shell脚本,可以提高工作效率,简化重复性的操作,减少人工干预,实现自动化的任务处理。同时,Shell脚本也是学习和理解操作系统的重要途径,可以深入了解操作系统的底层原理和机制。无论是系统管理员、开发人员还是普通用户,都可以通过学习和使用Shell脚本来提高工作效率和解决问题。
(三)Shell脚本的优势
1. 简单易学:Shell脚本语法简洁,易于理解和学习。即使没有编程经验的人也可以快速上手,编写出功能强大的脚本。
2. 强大的命令行工具:Shell脚本可以调用系统的各种命令行工具,如grep、sed、awk等,使得脚本能够处理各种文本文件、日志文件等。
3. 自动化任务:Shell脚本可以用于自动化执行一系列的任务,如备份文件、定时执行任务、批量处理数据等。通过编写脚本,可以节省大量的时间和精力。
4. 灵活性:Shell脚本可以根据不同的需求进行定制和扩展。可以通过变量、条件判断、循环等控制结构来实现不同的逻辑和功能。
5. 跨平台性:Shell脚本可以在不同的Unix和类Unix系统上运行,如Linux、Mac OS等。这使得脚本具有很好的可移植性,可以在不同的环境中使用和分享。
(四)shell应用场景
重复性操作
交互性任务
批量食物处理
服务运行状态监控
定时任务执行
注释:注释用于在脚本中添加说明和解释。以#
字符开头的行被视为注释,将被解释器忽略。
变量:变量用于存储数据。变量的命名区分大小写,通常使用大写字母。通过variable_name=value
来设置变量的值,使用$variable_name
来引用变量的值。
字符串:字符串是由字符组成的文本。可以使用单引号或双引号来定义字符串。双引号内的字符串可以包含变量和转义字符,而单引号内的字符串则原样输出。
输入输出:使用echo
命令输出文本,使用read
命令从用户获取输入。
基本运算:shell支持基本的数学运算,例如加法、减法、乘法和除法。
条件语句:使用if语句进行条件判断。if语句根据条件的真假来执行不同的代码块。
循环语句:使用for循环和while循环来执行重复的任务。for循环可以遍历列表或范围,而while循环在条件为真时执行。
函数:函数是一组被封装的代码块,可以在脚本中多次调用。使用function_name() { ... }
来定义函数,使用function_name
来调用函数。
条件测试:可以使用test命令或方括号进行条件测试。例如,if [ $a -eq $b ]
用于比较两个变量的值是否相等。
(一)shell
shell命令解释环境
类型
sh
ash
bsh
csh
bash
tcsh
dsh
zsh
查看系统中支持的shell
cat /etc/shells
查看系统默认shell
echo $SHELL
(二)变量
一)组成
1、变量名
不会变化
声明规范:不能是数字或数字开头;以_或字母开头;变量名中不能包含特殊字符
声明方法:
驼峰式 userName
双驼峰 UserName
shell写法:user_name;username;USERNAME
2、变量值
不断变化
承载的物体
数字、字符
二)类型
1、系统内置变量(环境变量):env
2、自定义变量:
varName=varValue
等号两边不能有空格
数字:var1=1
字符串:shell中可以不使用引号 当包含有空格时,需要使用引号
引号的用法:
不会引用变量值 单引号 '
会应用变量值 双引号 "
引用命令结果 反撇号 `
$(命令) 应用场景较多
3、位置变量:
脚本后参数所在的位置:$1 ... $9
预定义变量:
$0 脚本本身的名称
$# 脚本后参数的个数
$* 脚本运行时参数的内容(整体输出)
$@ 脚本运行时参数的内容(逐个输出)
$? 脚本运行完毕后的返回值,默认情况 0 成功,非0 失败
三)作用域
默认变量只在当前shell下生效
若要在当前及其子shell下生效,需要声明为全局变量:export
四)输出:echo $varName
五)shell中的字符串:string
赋值: str1=foodfornoting.gpg
1、获得字符串的长度
语法: ${#StringName}
案例: echo ${#str1}
输出结果:17
2、字符串取子串
语法: ${#StringName:position:lenght}
案例: echo ${str1:0:3}
输出结果:foo
注意:lenght没有定义时,一直取到字符串的结尾!
3、字符串的截取
a)从左至右截取最后一个匹配字符串string之后的所有字符串
语法: ${StringName##*string}
案例: echo ${str1##*fo}
输出结果:rnoting.gpg
b)从左至右截取第一个匹配字符串string之后的所有字符串
语法:${StringName#*string}
案例: echo ${str1#*fo}
输出结果:odfornoting.gpg
c)从右至左截取最后一个匹配字符串string之后的所有字符串
语法: ${StringName%%string*}
案例: echo ${str1%%o*}
输出结果:f
d)从右至左截取第一个匹配字符串string之后的所有字符串
语法: ${StringName%string*}
案例: echo ${str1%o*}
输出结果:foodforn
4、字符串的拼接
语法: StringName3=${StingName1}${StringName2}
案例:str1=Hello
str2=,Jack!
str3=${str1}${str2}
echo ${str3}
输出结果: Hello,Jack!
5、字符串替换:
语法: ${StringName/OldString/NewString}
案例: str1=foodfornoting.gpg
echo ${str1/oo/kk}
输出结果:fkkdfornoting.gpg
(三)运算符
一)数学运算 + - * / % * 作为乘号时需要加转义符\
运算方法
expr
expr $a + $b
$((a+b))
echo $((a+b))
$[a+b]
echo $[a+b]
注意 shell不支持浮点数的显示
二)比较运算
1、数值比较
-eq 等于
-ne 不等于
-lt 小于
-le 小于等于
-gt 大于
-ge 大于等于
2、字符串比较
= 字符串一致
!= 字符串不一致
-z 字符串为空
! -z 字符串不为空
3、文件比较
-e 文件或目录是否存在
-f 是否为文件
-d 是否为目录
-r 判断文件是否可读
-w 判断文件是否可写
-x 判断文件是否可执行
三)逻辑运算符
&&
[ $a -ne $b ] && echo OK 条件 && 输出结果 条件为真输出
||
[ $a -ne $b ] || echo OK 条件 || 输出结果 条件为假输出
-a 并且,有假则假,全真为真
-o 或者,有真则真,全假为假
! 取反 有真则假,有假则真
(一)shell脚本编写规范
第一行 #!/bin/bash
第二行 #脚本的说明
第三行 脚本正文
(二)shell运行规则
没有x权限
bash 脚本所在路径/脚本文件
source 脚本所在路径/脚本文件
. 脚本所在路径/脚本文件
脚本存在cd 时,会切换到目标目录
有x权限
./脚本文件
脚本绝对路径/脚本文件
(三)shell脚本运行追踪
bash -x 脚本所在路径/脚本文件
(四)read -p "提示语" 变量名 读取键盘输入并赋值给变量名
(五)语句
1)条件语句
1、单分支if
if [ ];then
fi
2、双分支if
if [ ];then
else
fi
3、多分支if
if [ ];then
elif [ ];then
else
fi
2)循环语句
1、for
for 条件(i in 值)|((i=1;i<=10;i++))
do
语句
done
2、while
i=1
while 条件
do
语句
let i++
done
关于$*与$@的验证
3)开关语句
1、case
case $1 in
条件1)
语句
;;
条件2)
语句
;;
*)
帮助信息
;;
esac
(六)文件操作四剑客
1)正则表达式
1、基础正则
创建test.txt
a)查找特定字符
cat test.txt | grep -n 'test'
b)利用[]查找集合字符
cat test.txt | grep -n 'sh[io]rt' 匹配i或者o
cat test.txt | grep -n '[^w]' 排除w
cat test.txt | grep -n '[a-h]oo'
cat test.txt | grep -n '[0-9]' 加点数字
c)查找行首"^"与行尾"$"
cat test.txt | grep -n '^[A-Z]'
cat test.txt | grep '\.$' \ 为转义符 .为任意符
d)查找任意一个字符"."与重复字符"*"
cat test.txt | grep -n 'w..d'
e)查找连续的字符范围"{}",需要使用转义符,"\{\}"
cat test.txt | grep -n 'o\{2\}'
cat test.txt | grep -n 'wo\{2,5\}d'
cat test.txt | grep -n 'wo\{2,\}d'
2、扩展正则
a)+,重复一个或一个以上的前一个字符
cat test.txt | grep -nE 'wo+d' 或者 cat test.txt | egrep -n 'wo+d'
b)?,零个或者一个前一个字符
cat test.txt | egrep -n 'bes?t'
c)|,使用或者的方式找出多个字符
cat test.txt | egrep -n 'of|is|on'
d)(),查找组字符串
cat test.txt | egrep -n 't(a|e)st'
e)()+,辨别多个重复的组
cat test.txt | egrep -n 'A(xyz)+C'
3、常见正则表达式
数字
“^[0-9]*[1-9][0-9]*$” //正整数
“^((-\d+)|(0+))$” //非正整数(负整数 + 0)
“^-[0-9]*[1-9][0-9]*$” //负整数
“^-?\d+$” //整数
“^\d+(\.\d+)?$” //非负浮点数(正浮点数 + 0)
“^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$” //正浮点数
“^((-\d+(\.\d+)?)|(0+(\.0+)?))$” //非正浮点数(负浮点数 + 0)
“^(-?\d+)(\.\d+)?$” //浮点数
字符串
“^[A-Z]+$” //由26个英文字母的大写组成的字符串
“^[a-z]+$” //由26个英文字母的小写组成的字符串
“^[A-Za-z0-9]+$” //由数字和26个英文字母组成的字符串
“^\w+$” //由数字、26个英文字母或者下划线组成的字符串
Email
“^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$” //email地址
“^([w-.]+)@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.)|(([w-]+.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(]?)$” //Email
Url
“^[a-zA-z]+://(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\S*)?$” //url
IP
“^(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5])$” //IP地址
Tel
/^((\+?[0-9]{2,4}\-[0-9]{3,4}\-)|([0-9]{3,4}\-))?([0-9]{7,8})(\-[0-9]+)?$/ //电话号码
日期校验
/^(d{2}|d{4})-((0([1-9]{1}))|(1[1|2]))-(([0-2]([1-9]{1}))|(3[0|1]))$/ // 年-月-日 yyyy-MM-dd / yy-MM-dd 格式
"^[0-9]{4}-((0([1-9]{1}))|(1[1|2]))-(([0-2]([0-9]{1}))|(3[0|1]))$" // 年-月- 日 yyyy-MM-dd 格式
/^((0([1-9]{1}))|(1[1|2]))/(([0-2]([1-9]{1}))|(3[0|1]))/(d{2}|d{4})$/ // 月/日/年
2)grep进阶
选项
-r
递归扫描指定目录下的每一个文件
-l
只显示匹配到指定关键字的文件名,而不是文件内容
案例
查看/etc目录下所有包含bash的文件名
grep -rl bash /etc
3)egrep 完美支持正则表达式
4)find进阶
按照权限查找
-perm
按照时间戳查找
-atime
-mtime
-ctime
-exec
find /var/spool/mail -type f -exec rm -rf {} \;
xargs
find /var/spool/mail -type f | xargs rm -rf
5)sed
语法
sed [选项] '操作' 参数
sed [选项] -f scriptfile 参数
选项
-e:表示用指定命令或脚本处理
-f:指定脚本文件
-h:帮助
-n:表示仅显示处理后的结果
-i:直接编辑文本文件
-r:支持扩展正则
重点
操作
a:增加,在当前行下面以行增加指定内容
c:替换,将选定行替换
d:删除,删除指定行
i:插入,在选定行的上面插入一行
p:打印
s:替换,替换指定字符
y:字符转换
重点
案例:
1.输出符合条件的文本:
sed -n 'p' test.txt #相当于cat
sed -n '3,6p' test.txt #打印第3到6行的内容
sed -n '1,6{p;n}' test.txt #打印1到6行之间的奇数行
sed -n '5,${p;n}' test.txt #从第5行开始打印奇数行
sed -n '/the/p' test.txt #匹配the
sed -n '5,/the/p' test.txt #匹配从第5行开始到包含the的行
sed -n '/the/,10p' test.txt #匹配从包含the的行到第10行结束
sed -n '/the/=' test.txt #打印包含the的行号
2.删除符合条件的文本
nl test.txt | sed '3d' #删除第3行
nl test.txt | sed '3,5d'
nl test.txt | sed '/the/d' #删除the所在行
3.替换符合条件的文本
nl test.txt | sed 's/the/TTTTTT/' #替换全文本
nl test.txt | sed '4s/the/TTTTTT/' #替换第4行
nl test.txt | sed 's/l/L/2' #替换匹配到的第2个l
4.迁移符合条件的文本
H:复制;g:覆盖;G:追加行;w:保存;r:读取;a:追加内容
sed '/the/{H;d};$G' test.txt #匹配the所在行并迁移至文件末尾
sed '3aTest' test.txt #在第3行下面新建行并写入Test
sed '/the/aTest' test.txt #匹配the所在行并在下一行写入Test
5.使用脚本编辑文件内容
vim opt.txt
1,5H
1,5d
16G
sed -f opt.txt test.txt #将1到5行迁移至16行后
6.以上修改想要直接修改文本源文件,只需要加入选项"-i"
6)awk
语法
awk 选项 '模式或条件{编辑命令}' 文件1 文件2 ...
awk -f 脚本文件 文件1 文件2 ...
选项: -F
指定每行的分隔符
默认分隔符为空格
内建变量
FS:指定每行的分隔符
NF:指定当前处理行的字段个数
NR:当前处理行的行号
$0:当前处理行的整行内容
$n:当前处理的第n个字段
FILENAME:处理文件名
RS:数据记录分隔,默认是\n
案例:
a)按行输出
awk '{print}' test.txt #等同cat
awk 'NR>=1&&NR<=3{print}' test.txt
awk 'NR==1,NR==3{print}' test.txt #打印1到3行
awk 'NR%2==0{print}' test.txt #打印偶数行
b)按段输出
默认以"空格"分段!
ifconfig ens33 |awk '/netmask/{print $2}' #筛选IP地址
cat /etc/shadow | awk -F : '$2=="!!"{print $1}' #打印不能登录系统的用户
c)调用shell命令
cat /etc/passwd | awk -F : '/bash$/{print | "wc -l"}' /etc/passwd #统计能够登录系统的用户个数