1. 正则表达式
正则表达式
2. Shell 文本处理工具
2.1. grep
grep
(Global Regular Expression Print) 是 Linux/Unix 系统中一个强大的文本搜索工具,用于在文件中查找包含特定模式的行。
基本语法
grep [选项] 模式 [文件...]
# 示例
grep "pattern" file.txt
Bash常用选项
-i, --ignore-case # 忽略大小写
-v, --invert-match # 反向查找,只显示不匹配的行
-n, --line-number # 显示匹配行的行号
-c, --count # 如果匹配成功,则输出匹配到多少行
-l, --files-with-matches # 如果匹配成功,则只将文件名打印出来,失败则不打印。通常 -r 一起用,grep -rl 'root' /etc
-R, -r, --recursive # 递归搜索目录
-w # 全词匹配,当你想搜索一个单词,但不想匹配到包含该单词的其他更长单词时使用。
-o, --only-matching # 只显示匹配的内容
-q, --quiet, --silent # 静默模式,不会向终端输出内容,得用$?来判断执行成功没有,即有没有过滤到想要的内容
-A, --after-context=NUM # 如果匹配成功,则将匹配行及其后n行一起打印出来
-B, --before-context=NUM # 如果匹配成功,则将匹配行及其前n行一起打印出来
-C, --context=NUM # 如果匹配成功,则将匹配行及其前后n行一起打印出来
-E # 使用扩展正则表达式 (等同于 egrep)
Bash高级用法示例
# 使用扩展正则表达式
grep -E "pattern1|pattern2" filename
# 搜索多个文件
grep "pattern" file1 file2 file3
# 将输出重定向到文件
grep "pattern" filename > output.txt
# 结合其他命令使用
ps aux | grep "process_name"
Bash实际应用示例
# 查找所有包含"error"的日志条目
grep -i "error" /var/log/syslog
# 统计Java代码中"public"关键字出现的次数
grep -c "public" *.java
# 查找当前目录及其子目录中所有包含"TODO"注释的文件
grep -rn "TODO" .
# 示配置文件中的非注释行
grep -v "^#" /etc/nginx/nginx.conf
# 查找包含IP地址的行
grep -E "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" file
Bash2.2. sed
sed
(Stream EDitor) 是一个强大的流式文本编辑器,用于对输入流(文件或管道)进行基本的文本转换。它以行为单位进行处理,可以将结果输出到标准输出或文件。
通俗来讲,sed 是一种在线的非交互式的编辑器,它一次只处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用 sed 命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出,或者使用 sed -i 选项,-i 选项就是将本该输出到屏幕上的内容输出/流入文件中。
模式空间与保持空间
模式空间 (Pattern Space):sed 的主要工作区 sed 每次读取一行文本到模式空间进行处理,大多数 sed 命令(如 s///
, p
, d
等)都是对模式空间进行操作。每处理完一行后自动清空,再读入下一行。
保持空间 (Hold Space):用于临时保存文本内容的额外缓冲区,用辅助模式空间处理文本。开始时为空,保存的内容会一直保留,直到被显式修改。
模式空间与保持空间使用案例:交换文件的行
cat test.txt
1111
2222
3333
# 实现步骤:
# 1、读取文件第一行内容到模式空间,进行的操作如下
# 将模式空间内容覆盖到保持空间
# 删除模式空间内容
# 2、读取文件第二行内容到模式空间,进行的操作如下
# 将保持内容追加到模式空间
# 将模式空间内容覆盖到保持空间
# 删除模式空间内容
# 3、读取文件第三行内容到模式空间,进行的操作如下
# 将保持空间内容追加到模式空间
# 命令
sed -r '1h;1d;2G;2h;2d;3G' test.txt
# 或者
sed '1!G;h;$!d' test.txt
Bash基本语法
sed [选项] '命令' 输入文件
sed [选项] -e '命令1' -e '命令2' 输入文件
sed [选项] -f 脚本文件 输入文件
Bash常用选项
-e # 允许多项编辑
-n # 禁止自动打印模式空间内容
-i # 直接修改文件内容
-r # 使用扩展正则表达式
-f # 指定sed脚本文件名
# 示例
# 演示文件
cat > test.txt <<EOF
1111111
2222222
3333333
4444444
5555555
EOF
# '' 空命令表示不执行任何编辑操作,仅打印模式空间内容
sed '' test.txt
1111111
2222222
3333333
4444444
5555555
# 对比添加 -n 参数
sed -n '' test.txt # 未输出任何内容
# 同时执行多条命令,d 表示删除,数字表示行数,命令详解见下一小结。
sed -e '3d' -e '1d' test.txt
2222222
4444444
5555555
# 查看源文件,发现没有修改文件
cat test.txt
1111111
2222222
3333333
4444444
5555555
# p 表示打印
sed -rn -e '1,3d' -e 'p' test.txt
4444444
5555555
# 对比不加 -n
sed -r -e '1,3d' -e 'p' test.txt
4444444
4444444
5555555
5555555 # 会自动打印模式空间内容,同时使用打印命令所以,会输出两次内容。
# 也可以将命令写入一个文件中
cat sed.txt
1,3d
p
sed -rn -f sed.txt test.txt
4444444
5555555
# 直接修改文件
sed -i -e '3d' -e '1d' test.txt
cat test.txt
2222222
4444444
5555555
Bash常用命令
命令的作用是告诉 sed 对指定行进行何种操作,包括打印、删除、修改等。
sed 命令由“地址+命令”两部分组成,命令如:1,3d,1,3 表示要处理的行数,d 表示执行什么操作。如果没有指定地址,sed 将处理所有行。
地址部分可以是数字也可以使用正则表达式,示例:
sed '3d' file.txt # 删除第3行
sed '2,5d' file.txt # 删除2-5行
sed '/^#/d' file.txt # 删除所有注释行(以#开头)
Bash基本操作命令:
s # 替换命令
sed 's/原字符串/新字符串/[flags]' 文件名
# flags 可以是:
# g:全局替换(一行中所有字符串都匹配,不加则匹配一行中的第一个)
# 数字:每行替换到第n个匹配
# p:打印替换的行
# w 文件:将替换的行写入文件
# i:忽略大小写
# 示例:只处理以数字开头的行,在这些行中,将所有 Apple 替换为 Orange,将修改后的这些行保存到 orange_lines.txt 文件中
sed '/^[0-9]/s/Apple/Orange/gw orange_lines.txt' test.txt
d # 删除命令
sed '/pattern/d' file.txt
p # 打印命令
# 通常与 -n 选项一起使用:
sed -n '/pattern/p' file.txt
q # 退出命令
sed '5q' file.txt # 处理前5行后退出
i # 在当前行之前添加一行或多行
sed '3i\插入内容' file.txt
a # 追加命令,在当前行后添加一行或多行
sed '/pattern/a\追加内容' file.txt
c # 用新文本修改(替换)当前行中的文本
sed '/pattern/c\新行内容' file.txt
r # 从文件读取内容并追加到匹配行后
sed '/pattern/r otherfile' file.txt
w # 将匹配行写入文件
sed '/pattern/w output.txt' file.txt
n # 把下一行内容读入模式空间,后续的处理命令处理的都是刚读入的新内容
sed '/pattern/{n;d}' file.txt # 删除匹配行的下一行
N # 将下一行追加到模式空间(两行合并)
sed 'N;s/\n/ /' file.txt # 合并连续两行
x # 交换模式空间和保持空间内容
h # 用模式空间覆盖保持空间
H # 将模式空间追加到保持空间
g # 用保持空间覆盖模式空间
G # 将保持空间追加到模式空间
l # 会用 $ 符号标识出文件中看不到的字符的位置
! # 对所选行以外的所有行应用命令
= # 打印行号
sed -n '/pattern/=' file.txt
y # 将字符转换为另一字符(字符一对一转换)
sed 'y/abc/ABC/' file.txt
Bash2.3. awk
awk 是一种强大的文本处理工具,主要用于模式扫描和处理,适用于结构化文本数据(如日志、CSV、表格数据等)。它支持变量、条件判断、循环、数组等编程特性,可以高效地提取、转换和格式化数据。
基本语法
awk [选项] '模式 {动作}' 输入文件
# 通过管道传递
command | awk '模式 {动作}'
Bash常用选项
-F # 指定字段分隔符(默认是空格或制表符)
-v # 定义变量(-v var=value)
-f # 从脚本文件读取 awk 命令
Bashawk 工作原理
# 示例
awk -F: '{print $1,$3}' /etc/passwd
# 1.awk 会接收一行作为输入,并将这一行赋给awk的内部变量$0,每一行也可称为一个记录,行的边界是以换行符作为结束。
# 2.然后,刚刚读入的行被以:为分隔符分解成若干字段(或域),每个字段存储在已编号的变量中,编号从$1开始,最多达100个字段。
# 注意:如果未指定行分隔符,awk将使用内置变量FS的值作为默认的行分隔符,FS默认值为空格
# 3.使用print函数打印,如果$1$3之间没有逗号,它俩在输出时将贴在一起,应该在$1,$3之间加逗号,该逗号与awk的内置变量OFS保持一致,OFS默认为空格,于是以空格为分隔符输出$1和$3
# 我们可以指定OFS的值:awk -F: 'BEGIN{OFS="-"}{print $1,$3}' /etc/passwd
# 4.输出之后,将从文件中获取另一行,然后覆盖给$0,继续重复上述步骤一直持续到所有行处理完毕。
Bash内置变量
$0 # 当前整行内容
$1, $2, ..., $NF # 以分隔符分隔的第 1、2、...、最后一个字段内容
NF # 当前行以分隔符分隔后的字段数
NR # 当前行号
FNR # 当前文件的行号(多文件处理时有用)
FS # 输入字段分隔符(默认空格)
OFS # 输出字段分隔符(默认空格)
RS # 输入记录(行)分隔符(默认 \n)
ORS # 输出记录(行)分隔符(默认 \n)
FILENAME # 当前处理的文件名
Bashawk 用法示例
# 打印整行
awk '{print $0}' file.txt
# 打印特定列
awk '{print $1, $3}' file.txt # 打印第1和第3列
# 指定分隔符
awk -F',' '{print $2}' data.csv # 以逗号分隔,打印第2列
# 条件过滤
awk '$3 > 100 {print $1, $3}' file.txt # 第3列大于100的行
awk '/error/ {print}' log.txt # 包含 "error" 的行
# 计算行数
awk 'END {print NR}' file.txt # 统计总行数
# 计算列总和
awk '{sum += $1} END {print sum}' file.txt
# BEGIN 和 END 块使用
awk 'BEGIN {FS=":"; OFS="|"} {print $1, $6} END {print "Total:", NR}' /etc/passwd
# 条件判断(if-else)
awk '{if ($3 > 50) print $1 " High"; else print $1 " Low"}' data.txt
# 循环(for/while)
awk '{for (i=1; i<=NF; i++) print $i}' file.txt # 逐字段打印
# 数组(统计词频)
awk '{count[$1]++} END {for (word in count) print word, count[word]}' file.txt
# 字符串操作
awk '{print length($1), substr($1, 2, 3), toupper($1)}' file.txt
# 多文件处理
awk '{print FILENAME, NR, $0}' file1.txt file2.txt
Bash3. 进程锁
进程锁(文件锁)在 Shell 脚本中用于确保同一时间只有一个脚本实例运行,防止资源竞争和数据损坏。以下是一种推荐实现方法:
#!/bin/bash
LOCK_FILE="/tmp/my_script.lock"
# 尝试获取锁,如果获取不到则退出
exec 200>"$LOCK_FILE"
flock -n 200 || {
echo "另一个实例正在运行,退出..."
exit 1
}
# 你的脚本主体代码
echo "脚本正在运行..."
sleep 10
# 自动释放锁(脚本结束时文件描述符关闭)
Bash