提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
前言
一、概述
1. 概念
2. 学习路径
2.1表达式
2.2 语句
2.3 函数
2.4 正则表达式
2.5 文件操作四剑客
二、表达式
1.shell
2.1 变量
2.2.1组成
2.2.2 类型
2.2.3 作用域
2.2.4 输出
2.2.5 shell中的字符串
2.2 运算符
2.3 shell脚本编写规范
2.4 shell运行规则
2.5 语句
2.5.1 条件语句
2.5.2 循环语句
2.5.3 开关语句
2. 文件操作四剑客
2.1 正则表达式
2.1.1 基础正则
2.1.2 扩展正则
2.1.3 常见正则表达式
2.2 grep进阶
2.3 find进阶
2.4 sed
2.5 awk
前言
今天学习的是Shell脚本的编写,Shell脚本是一种编写在Unix或类Unix操作系统上的脚本程序,用于执行一系列的命令。它由一系列的命令和控制结构组成,可以通过直接在命令行中输入脚本名称来执行,也可以通过给脚本文件添加执行权限后直接运行该文件。
Shell脚本通常用于自动化任务,可以编写一些简单或复杂的脚本来执行重复性的工作,提高工作效率。它可以像编程语言一样实现流程控制、变量定义、函数调用等功能。Shell脚本可以用多种脚本语言编写,如Bash、Csh、Ksh等,其中Bash是最常用的脚本语言。
使用Shell脚本可以实现很多任务,比如文件处理、系统管理、数据处理等。它可以调用系统命令、执行外部程序、处理输入输出、控制进程等。Shell脚本的优点是简单易学、灵活性强,但在处理大规模任务和复杂逻辑时可能效率较低,适用于快速编写和执行一些小规模任务。
提示:以下是本篇文章正文内容,下面案例可供参考
一、概述
1. 概念
脚本就是将手动一次性执行的命令进行规范且自动化
2. 学习路径
2.1表达式
变量 | 预定义变量 |
位置变量 | |
自定义变量 | |
运算符 | 数学运算 |
数值比较 | |
字符串比较 | |
文件判断 | |
布尔运算符 |
2.2 语句
条件语句 | if |
分支语句 | case |
循环语句 | for |
while |
2.3 函数
函数:函数是以函数名()跟{}括起来的内容组成。函数可以实现一些功能封装,同时函数也支持与脚本类似的参数解析逻辑。
2.4 正则表达式
标准正则
扩展正则
2.5 文件操作四剑客
find
egrep
sed
awk
二、表达式
1.shell
shell命令解释环境
类型
sh
ash
bsh
csh
bash
tcsh
dsh
zsh
查看系统中支持的shell
cat /etc/shells
查看系统默认shell
echo $SHELL
2.表达式
2.1 变量
2.2.1组成
变量名 | 不会变化 | 杯子 | |
瓢 | |||
容器... | |||
声明规范 | 不能是数字或数字开头 | ||
以_或字母开头 | |||
变量名中不能包含特殊字符 | |||
声明方法 | 驼峰式 | userName | |
双驼峰 | UserName | ||
shell写法 | user_name | ||
username | |||
USERNAME | |||
变量值 | 不断变化 | 承载的物体 | |
数字、字符 |
2.2.2 类型
系统内置变量(环境变量) | env |
自定义变量 | varName=varValue | |||
等号两边不能有格 | ||||
数字 | var1=1 | |||
字符串 | shell中可以不使用引号 | |||
当包含有空格时,需要使用引号 | ||||
引号的用法 | 不会引用变量值 | 单引号 | ' | |
会应用变量值 | 双引号 | " | ||
引用命令结果 | 反撇号 | ` | ||
$(命令) | 应用场景较多 |
位置变量 | 脚本后参数所在的位置 |
$1 | |
... | |
$9 |
预定义变量 | $0 | 脚本本身的名称 | |
$# | 脚本后参数的个数 | ||
$* | 脚本运行时参数的内容(整体输出) | ||
$@ | 脚本运行时参数的内容(逐个输出) | ||
$? | 脚本运行完毕后的返回值 | ||
默认情况 | 0 成功 | ||
非0 失败 |
2.2.3 作用域
默认变量只在当前shell下生效
若要在当前及其子shell下生效,需要声明为全局变量
export
2.2.4 输出
echo $varName
2.2.5 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 ${str2%%o*}
输出结果:f
d)从右至左截取第一个匹配字符串string之后的所有字符串
语法: ${StringName%string*}
案例: echo ${str2%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
2.2 运算符
数学运算
数学运算 | + - * / % | * 作为乘号时需要加转义符\ | |
运算方法 | expr | expr $a + $b | |
$((a+b)) | echo $((a+b)) | ||
$[a+b] | echo $[a+b] | ||
注意 | shell不支持浮点数的显示 |
比较运算
条件测试 | test var1 比较符 var2 | ||
[ var1 比较符 var2 ] | |||
&& | [ $a -ne $b ] && echo OK | 条件 && 输出结果 | |
条件为真输出 | |||
|| | [ $a -ne $b ] || echo OK | 条件 || 输出结果 | |
条件为假输出 |
数值比较
-eq | 等于 |
-ne | 不等于 |
-lt | 小于 |
-le | 小于等于 |
-gt | 大于 |
-ge | 大于等于 |
字符串比较
= | 字符串一致 |
!= | 字符串不一致 |
-z | 字符串为空 |
! -z | 字符串不为空 |
文件比较
-e | 文件或目录是否存在 |
-f | 是否为文件 |
-d | 是否为目录 |
-r | 判断文件是否可读 |
-w | 判断文件是否可写 |
-x | 判断文件是否可执行 |
逻辑运算符
&& | -a | 并且,有假则假,全真为真 | [ -r 111 -a -w 111 -a -x 111 ] |
[ -r 111 ] && [ -w 111 ] && [ -x 111 ] | |||
[ -x /root/file1 -a -d /root/file1 ] | |||
[ -x /root/file1 ] && [ -d /root/file1 ] | |||
|| | -o | 或者,有真则真,全假为假 | |
! | 取反 | 有真则假,有假则真 |
2.3 shell脚本编写规范
第一行
#!/bin/bash
第二行
#脚本的说明
第三行
脚本正文
2.4 shell运行规则
没有x权限 | bash 脚本所在路径/脚本文件 | |
source 脚本所在路径/脚本文件 | 脚本存在cd 时,会切换到目标目录 | |
. 脚本所在路径/脚本文件 | ||
有x权限 | ./脚本文件 | |
脚本绝对路径/脚本文件 |
shell脚本运行追踪
bash -x 脚本所在路径/脚本文件
$[$RANDOM%100]
返回100内随机数
seq 1 10
返回1到10 的连续数字
{1..10}
返回1到10 的连续数字
seq 1.1 10.1
返回1.1 2.1 3.1.... 10.1
read -p "提示语" 变量名
读取键盘输入并赋值给变量名
2.5 语句
2.5.1 条件语句
单分支if
if [ ];then
fi
双分支if
if [ ];then
else
fi
多分支if
if [ ];then
elif [ ];then
else
fi
2.5.2 循环语句
for
for 条件(i in 值)|((i=1;i<=10;i++))
do
语句
done
while
i=1
while 条件
do
语句
let i++
done
关于$*与$@的验证
2.5.3 开关语句
case
case $1 in
条件1)
语句
;;
条件2)
语句
;;
*)
帮助信息
;;
esac
nginx启动脚本
2. 文件操作四剑客
2.1 正则表达式
2.1.1 基础正则
a)查找特定字符
cat test.txt | grep -n 'was'
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'
cat test.txt | grep -n 'ooo*'
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.1.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'
2.1.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.2 grep进阶
选项
-r
递归扫描指定目录下的每一个文件
-l
只显示匹配到指定关键字的文件名,而不是文件内容
案例
查看/etc目录下所有包含bash的文件名
grep -rl bash /etc
egrep
完美支持正则表达式
2.3 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
2.4 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 '3p' test.txt #打印第3行
sed -n '3,6p' test.txt #打印第3到6行的内容
sed -n 'p;n' test.txt #打印奇数行
sed -n 'n;p' test.txt #打印偶数行
sed -n '1,6{p;n}' test.txt #打印1到6行之间的奇数行
sed -n '5,${p;n}' test.txt #从第5行开始打印奇数行
sed -n '/goo/p' test.txt #匹配goo
sed -n '5,/goo/p' test.txt #匹配从第5行开始到包含goo的行
sed -n '/goo/,10p' test.txt #匹配从包含goo的行到第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 '3s/good/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"
2.5 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 #统计能够登录系统的用户个数
总结
Shell脚本是一种文本文件,由一系列命令和控制结构组成,用于执行一系列的任务。
Shell脚本可以通过直接在命令行中输入脚本名称来执行,也可以通过给脚本文件添加执行权限后直接运行该文件。
Shell脚本可以用多种脚本语言编写,如Bash、Csh、Ksh等,其中Bash是最常用的脚本语言。
Shell脚本可以调用系统命令、执行外部程序、处理输入输出、控制进程等。
Shell脚本可以实现文件处理、系统管理、数据处理等多种任务。
Shell脚本具有简单易学、灵活性强的特点,适用于快速编写和执行一些小规模任务。
Shell脚本的效率可能较低,适用于处理小规模任务和简单逻辑,对于大规模任务和复杂逻辑,可能效率较低。
Shell脚本是Unix系统中常用的自动化工具,广泛应用于系统管理、软件开发等领域。
总而言之,Shell脚本是一种简单、灵活的自动化工具,能够帮助我们自动化执行任务,提高工作效率。