第9章 Shell编程
📝 Linux学习笔记 - 第9章 🎯 共5节
本章目录
基础正则表达式
正则表达式与通配符
- 正则表达式用来在文件中匹配符合条件的字符串,正则是包含匹配
- 通配符用来匹配符合条件的文件名,通配符是完全匹配
注意:
ls、find、cp这些命令不能用正则,只能用通配符
基础正则表达式
| 元字符 | 作用 |
|---|---|
| * | 前一个字符匹配0次或任意多次 |
| . | 匹配除了换行符外任意一个字符 |
| ^ | 匹配行首。例如:^hello会匹配以hello开头的行 |
| $ | 匹配行尾。例如:hello$会匹配以hello结尾的行 |
| [] | 匹配中括号中指定的任意一个字符,只匹配一个字符。例如:[aoeiu] 匹配任意一个元音字母,[0-9] 匹配任意一位数字,[a-z][0-9]匹配小写字和一位数字构成的两位字符 |
| [^] | 匹配除中括号的字符以外的任意一个字符。例如:[^0-9] 匹配任意一位非数字字符,[^a-z] 匹配任意一位非小写字母 |
| \ | 转义符。用于取消特殊符号的含义 |
| \{n\} | 表示其前面的字符恰好出现n次。例如:[0-9]\{4\} 匹配4位数字 |
| \{n,\} | 表示其前面的字符出现不小于n次。例如:[a-z]\{5,\} 匹配5位及以上的小写字母 |
| \{n,m\} | 表示其前面的字符至少出现n次,最多出现m次。例如:[a-z]\{5,8\} 匹配5到8位的小写字母 |
示例:
grep "a*" test.txt
# 匹配所有内容,包括空白行
grep "aa*" test.txt
# 匹配至少包含有一个a的行
grep "aaa*" test.txt
# 匹配至少包含有两个a连续的行
grep "s..d" test.txt
# 匹配s和d之间有两个任意字符的行
grep "^M" test.txt
# 匹配以M开头的行
grep "n$" test.txt
# 匹配以n结尾的行
grep "^$" test.txt
# 匹配空白行
grep "s[ao]id" test.txt
# 匹配s和id中间是a或o的行
grep "[0-9]" test.txt
# 匹配包含数字的行
grep "^[^a-z]" test.txt
# 匹配不以小写字母开头的行
grep "\.$" test.txt
# 匹配以.结尾的行
grep "a\{3\}" test.txt
# 匹配包含连续3个a的行
grep "[0-9]\{3,\}" test.txt
# 匹配包含3个及以上连续数字的行字符截取命令
cut字段提取命令
cut [选项] 文件名| 选项 | 说明 |
|---|---|
| -f 列号 | 提取第几列 |
| -d 分隔符 | 按照指定分隔符分割列 |
示例:
cut -f 2 test.txt
# 提取第二列
cut -d ":" -f 1,3 /etc/passwd
# 以冒号为分隔符,提取第1和第3列cut命令的局限:如果分隔符是空格,而且空格数量不固定,cut就不好用了
printf命令
printf '输出类型输出格式' 输出内容输出类型:
| 类型 | 说明 |
|---|---|
| %ns | 输出字符串。n是数字指代输出几个字符 |
| %ni | 输出整数。n是数字指代输出几个数字 |
| %m.nf | 输出浮点数。m和n是数字,指代输出的整数位数和小数位数 |
输出格式:
| 格式 | 说明 |
|---|---|
| \a | 输出警告声音 |
| \b | 输出退格键,也就是Backspace键 |
| \f | 清除屏幕 |
| \n | 换行 |
| \r | 回车,也就是Enter键 |
| \t | 水平输出退格键,也就是Tab键 |
| \v | 垂直输出退格键,也就是Tab键 |
示例:
printf '%s\t%s\t%s\n' 1 2 3 4 5 6awk命令
awk的使用
awk '条件1{动作1} 条件2{动作2}...' 文件名条件(Pattern):
- 一般使用关系表达式作为条件
- x > 10 判断变量x是否大于10
- x >= 10 大于等于
- x ⇐ 10 小于等于
动作(Action):
- 格式化输出
- 流程控制语句
示例:
awk '{printf $2 "\t" $4 "\n"}' test.txt
# 输出第2列和第4列
df -h | awk '{print $1 "\t" $5}'
# 查看磁盘使用情况,输出第1列和第5列BEGIN
awk 'BEGIN{printf "This is a transcript\n"} {printf $2 "\t" $4 "\n"}' test.txt
# 在所有内容输出之前,先输出一句话END
awk 'END{printf "The End\n"} {printf $2 "\t" $4 "\n"}' test.txt
# 在所有内容输出之后,输出一句话FS内置变量
cat /etc/passwd | grep "/bin/bash" | awk 'BEGIN{FS=":"} {printf $1 "\t" $3 "\n"}'
# FS指定分隔符,BEGIN是因为awk会先读第一行再执行关系运算符
cat test.txt | grep -v Name | awk '$4 >= 87 {printf $2 "\n"}'
# 第四列大于等于87的行,输出第二列sed命令
sed是一种几乎包括在所有UNIX平台(包括Linux)的轻量级流编辑器。sed主要是用来将数据进行选取、替换、删除、新增的命令。
sed [选项] '[动作]' 文件名| 选项 | 说明 |
|---|---|
| -n | 一般sed命令会把所有数据都输出到屏幕,如果加入此选择则只会把经过sed命令处理的行输出到屏幕 |
| -e | 允许对输入数据应用多条sed命令编辑 |
| -i | 用sed的修改结果直接修改读取数据的文件,而不是由屏幕输出 |
| 动作 | 说明 |
|---|---|
| a \ | 追加,在当前行后添加一行或多行。添加多行时,除最后一行外,每行末尾需要用""代表数据未完结 |
| c \ | 行替换,用c后面的字符串替换原数据行,替换多行时,除最后一行外,每行末尾需用""代表数据未完结 |
| i \ | 插入,在当期行前插入一行或多行。插入多行时,除最后一行外,每行末尾需要用""代表数据未完结 |
| d | 删除,删除指定的行 |
| p | 打印,输出指定的行 |
| s | 字串替换,用一个字符串替换另外一个字符串。格式为”行范围s/旧字串/新字串/g” |
示例:
sed -n '2p' test.txt
# 查看文件的第二行
sed '2,4d' test.txt
# 删除第二行到第四行,但不修改文件本身
sed '2a hello' test.txt
# 在第二行后追加hello
sed '2i hello \
world' test.txt
# 在第二行前插入两行数据
sed '4c No such person' test.txt
# 替换第四行整行数据
sed '4s/75/99/g' test.txt
# 替换第四行中的75为99
sed -i '4s/75/99/g' test.txt
# -i会直接修改文件字符处理命令
排序命令sort
sort [选项] 文件名| 选项 | 说明 |
|---|---|
| -f | 忽略大小写 |
| -n | 以数值型进行排序,默认使用字符串型排序 |
| -r | 反向排序 |
| -t | 指定分隔符,默认是分隔符是制表符 |
| -k n[,m] | 按照指定的字段范围排序。从第n字段开始,m字段结束(默认到行尾) |
示例:
sort /etc/passwd
# 排序用户信息文件
sort -r /etc/passwd
# 反向排序
sort -t ":" -k 3,3 /etc/passwd
# 指定分隔符是冒号,用第三字段排序(按字符串排序)
sort -n -t ":" -k 3,3 /etc/passwd
# 按数值排序统计命令wc
wc [选项] 文件名| 选项 | 说明 |
|---|---|
| -l | 只统计行数 |
| -w | 只统计单词数 |
| -m | 只统计字符数 |
示例:
wc /etc/passwd
# 统计行数、单词数、字符数
wc -l /etc/passwd
# 只统计行数条件判断
按照文件类型进行判断
| 测试选项 | 作用 |
|---|---|
| -b 文件 | 判断该文件是否存在,并且是否为块设备文件(是块设备文件为真) |
| -c 文件 | 判断该文件是否存在,并且是否为字符设备文件(是字符设备文件为真) |
| -d 文件 | 判断该文件是否存在,并且是否为目录文件(是目录为真) |
| -e 文件 | 判断该文件是否存在(存在为真) |
| -f 文件 | 判断该文件是否存在,并且是否为普通文件(是普通文件为真) |
| -L 文件 | 判断该文件是否存在,并且是否为符号链接文件(是符号链接文件为真) |
| -p 文件 | 判断该文件是否存在,并且是否为管道文件(是管道文件为真) |
| -s 文件 | 判断该文件是否存在,并且是否为非空(非空为真) |
| -S 文件 | 判断该文件是否存在,并且是否为套接字文件(是套接字文件为真) |
两种判断格式:
test -e /root/install.log
# 或者
[ -e /root/install.log ]
# 注意:中括号内部两边必须有空格判断是否为真:
[ -d /root ] && echo "yes" || echo "no"
# 判断/root是否为目录按照文件权限进行判断
| 测试选项 | 作用 |
|---|---|
| -r 文件 | 判断该文件是否存在,并且是否该文件拥有读权限(有读权限为真) |
| -w 文件 | 判断该文件是否存在,并且是否该文件拥有写权限(有写权限为真) |
| -x 文件 | 判断该文件是否存在,并且是否该文件拥有执行权限(有执行权限为真) |
| -u 文件 | 判断该文件是否存在,并且是否该文件拥有SUID权限(有SUID权限为真) |
| -g 文件 | 判断该文件是否存在,并且是否该文件拥有SGID权限(有SGID权限为真) |
| -k 文件 | 判断该文件是否存在,并且是否该文件拥有SBit权限(有SBit权限为真) |
两个文件之间进行比较
| 测试选项 | 作用 |
|---|---|
| 文件1 -nt 文件2 | 判断文件1的修改时间是否比文件2的新(如果新则为真) |
| 文件1 -ot 文件2 | 判断文件1的修改时间是否比文件2的旧(如果旧则为真) |
| 文件1 -ef 文件2 | 判断文件1是否和文件2的Inode号一致,可以理解为两个文件是否为同一个文件。这个判断用于判断硬链接是很好的方法 |
两个整数之间比较
| 测试选项 | 作用 |
|---|---|
| 整数1 -eq 整数2 | 判断整数1是否和整数2相等(相等为真) |
| 整数1 -ne 整数2 | 判断整数1是否和整数2不相等(不相等为真) |
| 整数1 -gt 整数2 | 判断整数1是否大于整数2(大于为真) |
| 整数1 -lt 整数2 | 判断整数1是否小于整数2(小于为真) |
| 整数1 -ge 整数2 | 判断整数1是否大于等于整数2(大于等于为真) |
| 整数1 -le 整数2 | 判断整数1是否小于等于整数2(小于等于为真) |
字符串的判断
| 测试选项 | 作用 |
|---|---|
| -z 字符串 | 判断字符串是否为空(为空返回真) |
| -n 字符串 | 判断字符串是否为非空(非空返回真) |
| 字串1 == 字串2 | 判断字符串1是否和字符串2相等(相等返回真) |
| 字串1 != 字串2 | 判断字符串1是否和字符串2不相等(不相等返回真) |
多重条件判断
| 测试选项 | 作用 |
|---|---|
| 判断1 -a 判断2 | 逻辑与,判断1和判断2都成立,最终的结果才为真 |
| 判断1 -o 判断2 | 逻辑或,判断1和判断2有一个成立,最终的结果就为真 |
| !判断 | 逻辑非,使原始的判断式取反 |
流程控制
if语句
单分支if条件语句
if [ 条件判断式 ]; then
程序
fi或者
if [ 条件判断式 ]
then
程序
fi示例:
#!/bin/bash
rate=$(df -h | grep /dev/sda3 | awk '{print $5}' | cut -d "%" -f 1)
if [ $rate -ge 80 ]
then
echo "Warning! /dev/sda3 is full!"
fi双分支if条件语句
if [ 条件判断式 ]
then
条件成立时,执行的程序
else
条件不成立时,执行的另一个程序
fi示例:
#!/bin/bash
# 判断apache是否启动
port=$(nmap -sT 192.168.1.156 | grep tcp | grep http | awk '{print $2}')
if [ "$port" == "open" ]
then
echo "$(date) httpd is ok!" >> /tmp/autostart-acc.log
else
/etc/rc.d/init.d/httpd start &>/dev/null
echo "$(date) restart httpd !!" >> /tmp/autostart-err.log
fi多分支if条件语句
if [ 条件判断式1 ]
then
当条件判断式1成立时,执行程序1
elif [ 条件判断式2 ]
then
当条件判断式2成立时,执行程序2
...省略更多分支...
else
当所有条件都不成立时,最后执行此程序
fi示例:
#!/bin/bash
# 判断用户输入的是什么文件
read -p "Please input a filename: " file
if [ -z "$file" ]
then
echo "Error, please input a filename"
exit 1
elif [ ! -e "$file" ]
then
echo "Your input is not a file!"
exit 2
elif [ -f "$file" ]
then
echo "$file is a regular file!"
elif [ -d "$file" ]
then
echo "$file is a directory!"
else
echo "$file is an other file!"
ficase语句
case语句和if…elif…else语句一样都是多分支条件语句,不过和if多分支条件语句不同的是,case语句只能判断一种条件关系,而if语句可以判断多种条件关系。
case $变量名 in
"值1")
如果变量的值等于值1,则执行程序1
;;
"值2")
如果变量的值等于值2,则执行程序2
;;
...省略其他分支...
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac示例:
#!/bin/bash
read -p "Please choose yes/no: " -t 30 cho
case $cho in
"yes")
echo "Your choose is yes!"
;;
"no")
echo "Your choose is no!"
;;
*)
echo "Your choose is error!"
;;
esacfor循环
语法一
for 变量 in 值1 值2 值3...
do
程序
done示例:
#!/bin/bash
# 打印时间
for time in morning noon afternoon evening
do
echo "This time is $time!"
done语法二
for (( 初始值;循环控制条件;变量变化 ))
do
程序
done示例:
#!/bin/bash
# 从1加到100
s=0
for (( i=1;i<=100;i=i+1 ))
do
s=$(( $s+$i ))
done
echo "The sum of 1+2+...+100 is : $s"while循环
while循环是不定循环,也称作条件循环。只要条件判断式成立,循环就会一直继续,直到条件判断式不成立,循环才会停止。
while [ 条件判断式 ]
do
程序
done示例:
#!/bin/bash
# 从1加到100
i=1
s=0
while [ $i -le 100 ]
do
s=$(( $s+$i ))
i=$(( $i+1 ))
done
echo "The sum is: $s"until循环
until循环,和while循环相反,until循环时只要条件判断式不成立则进行循环,并执行循环程序。一旦循环条件成立,则终止循环。
until [ 条件判断式 ]
do
程序
done示例:
#!/bin/bash
# 从1加到100
i=1
s=0
until [ $i -gt 100 ]
do
s=$(( $s+$i ))
i=$(( $i+1 ))
done
echo "The sum is: $s"