《Linux命令行与shell脚本编程大全》笔记3

本文深入探讨sed和gawk的高级应用,包括多行命令处理、模式空间与保持空间操作、变量与数组使用、正则表达式匹配及结构化命令应用。通过实例展示如何高效处理复杂文本数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

sed进阶
多行命令
sed的局限在于只能针对单行数据执行操作。在sed读取数据流时,它会基于换行符的位置将数据分成行。
如果你正在查找一个短语Linux System Administrators Group,它很可能出现在两行之中,每行各包含一部分短语。如果用普通的sed命令处理文件,就不能发现这种被分开的短语。

处理多行文本的特殊命令
N将数据流中的下一行加进来创建一个多行组(multiline group)处理
D删除多行组中的一行
P打印多行组中的一行

next命令
1.单行的next命令
n命令(小写)会让sed移动到数据流中的下一行文本。
现在你有一个数据文件。
在这里插入图片描述
目标是删除首行空白之后的空白行,而留下最后一行之前的空白行
sed '/^$/d' data1.txt 这么做会删掉两个空白行
在这里插入图片描述
sed '/header/{n ; d}' data1.txt 先找到含有head的一行,在移动到它的下一行(第一个空白行)在用d命令删除空白行
在这里插入图片描述
2.合并文本行
N命令(大写)会将下一个文本行添加到模式空间已有的文本后。这样就能将数据流的两个文本行合并到同一个模式空间中。文本行仍然是用换行符分割的,但sed会将两行文本当做一行来处理。
现在有一个数据文件。
在这里插入图片描述
要把第二行和第三行合并为同一行。sed先找到含有first的一行(第二行),N命令将下一行(第三行)合并到这一行。然后用替换命令s将换行符替换成空格。
sed '/first/{N;s/\n/ /}' data2.txt
在这里插入图片描述
现在有一个数据文件。
在这里插入图片描述
在文件中查找Sysem Administrator 然后将它替换成Desktop User
sed 'N;s/System.Administrator/Desktop User/' data3.txt 用N命令将第一行和下一行合并起来。点号匹配空格和换行符这两种情况
在这里插入图片描述
但这样会把两行合并为一行。解决方法是在sed中脚本中用两个替换命令:一个用来匹配多行,另一个用啦匹配单行

sed 'N
s/System\nAdministrator/Desktop\nUser/
s/System Adiministrator/Desktop User/' data3.txt

3.多行删除命令
d命令用来删除模式空间中的当前行。
删除命令会将含有分开短语的两行都删掉。
sed 'N;/System\nAdministrator/d' data4.txt
在这里插入图片描述
D删除命令只会删除模式空间中的第一行,文本的第二行被 N 命令加到了模式空间,但仍然完好。
sed 'N;/System\nAdiministrator/D' data4.txt
在这里插入图片描述
这里有一个数据文本
在这里插入图片描述
删除数据流中出现的第一行前的空白行。先查找空白行,再用N命令将下以文本行添加到模式空间。如果新的模式空间内容含有单词header。则D命令会删除该模式空间的第一行。
sed '/^$/{N;/header/D}' data5.txt
4.多行打印命令
P命令(大写)只打印多行模式空间中的第一行。
sed -n 'N;/System\nAdministrator/P' data3.txt
在这里插入图片描述
保持空间
模式空间(pattern space)是一块活跃的缓冲区,在执行sed命令时里面保存了要检查的文本。
保持空间(hold space),在处理模式空间中某些行时可以用来临时保存一些行。

commanddescription
h将模式空间复制到保持空间
H将模式空间附加到保持空间
g将保持空间复制到模式空间
G将保持空间附加到模式空间
x交换模式空间和附加空间的内容

这里有一个文件
在这里插入图片描述
sed -n '/first/{h;p;n;p;g;p}' data2.txt
在这里插入图片描述
sed先用正则表达式过滤出含有first的行;当含有first的行出现时,h命令将该行放到保持空间中;
p命令打印模式空间第一行;n命令提取数据流中的第一行并用p命令打印出来;g命令将保持空间的内容放回模式空间中;在用p命令打印模式空间当前内容

排除命令
感叹号命令(!)用来排除命令,也就是会让原本会起作用的命令不起作用。
将一个文件出除了包含单词header那一行都打印出来
sed -n '/header/!p' data.txt
sed无法处理数据流中的最后一行解决方法:美元符表示数据流中的最后一行文本,所以当sed编辑器到了最后一行时,它没有执行 N 命令,但它对所有其他行都执行了这个命令。使用这种方法,你可以反转数据流中文本行的顺序。要实现这个效果(先显示最后一行,最后显
示第一行)
sed '$!N' data.txt

改变流
(1)分支
基于地址、地址模式或地址区间排除一整块命令、
[address]b [label]

optiondescription
address决定哪些行的数据会触发分支命令
label定义要跳转的位置;如果没有这个参数会跳转到结尾

这里有一个文本数据
在这里插入图片描述
分支命令在数据流中的第2行和第3行处跳过两个替代命令
sed '{2,3b;s/This is/Is this/;s/line/test ?/}' data2.txt
在这里插入图片描述
要是不想直接跳到脚本的结尾,可以定义一个Label;Label以冒号开始,最多可以7个字符长度:label2
如果文本文件出现了first,程序跳转到标签jump1的脚本行;除了含有first的行都进行第一次替换;
:jump1 跳回匹配行 进行第二次替换

sed '{/first/b jump1;s/This is the/Np jump on/
:jump1
s/This is the/Jump here on/}' data2.txt

在这里插入图片描述
测试
测试(test)命令(t)可以改变sed脚本执行流程
格式:[address] t [label]
这里有一个文本数据
在这里插入图片描述
第一个替换命令会查找模式文本 first 。如果匹配了行中的模式,它就会替换文本,而且测试命
令会跳过后面的替换命令。如果第一个替换命令未能匹配模式,第二个替换命令就会被执行。

sed '{
s/first/matched/ #进行第一次替换的 跳过后面的替换命令
t
s/This is the/No match on/}' data2.txt #第一次跳过的行进行该替换

在这里插入图片描述

模式替换
想在行中匹配的单词两边上放上引号
echo "The cat sleeps in his hat" | sed 's/cat/"cat"/'
在这里插入图片描述
如果想在模式用点符号匹配多个单词,这么做就会出错。
echo "The cat sleeps in his hat" | sed 's/.at/".at"/g'
在这里插入图片描述
&符号
&符号可以用来代表替换命令的匹配的模式。
echo "The cat sleeps in his hat" | sed 's/.at/"&"/g'
在这里插入图片描述
替换单独的单词
sed用圆括号来定义替换模式中的子模式。可以在替换模式中使用的在特殊字符来引用每个子模式。替换字符由反斜线和数字(\n)组成。数字表明子模式的位置。
当在替换命令中使用圆括号时,必须用转义字符将它们标示为分组字符而不是普通的圆括号。
echo "The System Administrator manual " | sed 's/\(System\) Administrator/\1 User/'
在这里插入图片描述
sed实用工具
(1)加倍行间距
向一个文本文件的行间插入空白行:G命令
sed 'G' data2.txt
在这里插入图片描述
不想要在最后一行插入空白行
sed '$!G' data2.txt
(2)对可能含有空白行的文件加倍行间距
有一个文本文件已经有一些空白行
在这里插入图片描述
sed '{/^$/d;$!G}' data6.txt
在这里插入图片描述
(3)给文件中的行编号
用等号显示数据流中行的行号
sed '=' data2.txt
在这里插入图片描述
sed '=' data2.txt | sed 'N;s/\n/ /'
在这里插入图片描述
(4)打印末尾行
sed -n '$p' data
(5)删除行
删除连续的空白行
sed '/./,/^$/!d' data.txt
删除开头的空白行
sed '/./,$!d' data.txt

gawk进阶
使用变量:内建变量

variabledescription
FIELDWIDTHS由空格分割的一段数字,定义每个数字字段确切的宽度
FSField separator;输入字段分割符
RSRecord separator;输入记录分割符
OFSoutput Field separator;输出字段分割符
ORSoutput Record separator;输出记录分割符

这里有一个数据文件
在这里插入图片描述
gawk 'BEGIN{FS=","}{print $1,$2,$3}' data1.txt
在这里插入图片描述
gawk 'BEGIN{FS=",";OFS="-"}{print $1,$2,$3}' data1.txt
在这里插入图片描述
FIELDWIDTH变量可以设置来匹配数据在记录中的位置
这里有一个文件
在这里插入图片描述
gawk 'BEGIN{FIELDWIDTH="3 5 2 5"}{print $1,$2,$3,$4}' data1b
FIELDWIDTH变量定义了四个字端,gawk依次来解析数据记录。每个记录中的数字串会根据已定义好的字段长度来分割。
在这里插入图片描述
在这里插入图片描述
变量RS和ORS等定义了gawk如何处理数据流中的字段。默认情况下,gawk将 RS 和 ORS 设为换行符。默认的 RS 值表明,输入数据流中的每行新文本就是一条新纪录。
有时在数据流中会碰到占据多行的字段。
在这里插入图片描述
gawk默认会将每行当做一条单独的记录来读(RS),将记录中的空格当做字段的分隔符(FS);解决方法是将FS设为换行符,RS设为空白行
更多的gawk的内建变量

varIabledescription
ARGV包含命令行参数的数组
ARGC当前命令行参数的个数
ARGIND当前文件在ARGV中的位置
CONVFMTconvert forma;数字的转换格式
ENVIRON当前shell环境变量及其值组成的关联数组
ERRNO当读取或关闭输入文件发生错误的系统错误号
FILENAME用作gawk输入数据的数据文件的文件名
FNR当前数据文件的数据行数
IGNORECASE
NF数据文件中的字符总数
NR已处理的输入记录数
OFMToutput format;数字的输出格式
RLENGTH由match函数匹配的子字符串的长度
RSTART由natch函数所匹配的子字符串的起始位置

ARGC表明命令行上有两个参数。分别是gawk命令和data1参数
ARGV数组从索引0开始。

gawk 'BEGIN{print ARGC,ARGV[1]}' data1
2 data1

ENVRION数组索引是shell环境变量名,值是shell环境变量的值。

gawk'BEGIN{print ENVIRON["HOME"];print ENVIRON["PATH"]}'
/home/rich
/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin

NF可以告诉你记录中有多少个数据字段,$NF可以在不知道具体位置的情况下制定记录中的最后一个数据字段。
gawk 'BEGIN{FS=":";OFS=":"}{print $1,$NF}' /etc/passwd
在这里插入图片描述
FNR变量含有当前数据文件已处理过的记录数,NR变量则含有已处理过得当前记录数。
gawk 'BEGIN{FS=","}{print $1,"FNR="FNR}' data1 data1
在这里插入图片描述
gawk 'BEGIN{FS=","}{print $1,"FNR="FNR,"NR="NR}' data1 data1
在这里插入图片描述
FNR变量的值在gawk处理第二个数据文件时会被重置重新计数。
NR变量的值在处理第二个数据文件时继续计数。
如果只使用一个数据文件作为输入, FNR 和 NR 的值是相同的;如果使用多个数据文件作为输入, FNR 的值会在处理每个数据文件时被重置,而 NR 的值则会继续计数直到处理完所有的数据文件。

自定义变量
(1)在脚本中给变量赋值
gawk变量可以保存数值或文本值
gawk 'BEGIN{testing="This is a test";print testing}'
变量可以改变
gawk 'BEGIN{name="kiko";print name;name="keiji";print name}'
赋值语句还可以包含数学算式来处理数字值
gawk 'BEGIN{x=4;x=x*2+3;print x}'
(2)在命令行上给变量赋值

#这里有一个脚本script1
BEGIN{FS=","}
{print $n}
#gawk运行指定脚本
打印文件第二列数据
gawk -f script1 n=2 data1
打印文件第三列数据
gawk -f script1 n=3 data1

使用命令行参数来定义变量值会有一个问题。在你设置变量后,这个值在代码的BEGIN部分不可用。

#这里有一个脚本script2
BEGIN{print "The starting value is",n;FS=","}
{print $n}
#用gawk指定运行脚本
gawk -f script2 n=3 data1

在这里插入图片描述
gawk可以用-v来设定变量,-v命令行参数必须放在脚本代码之前
gawk -v n=3 -f script2 data1
在这里插入图片描述
处理数组
gawk中的关联数组,它的索引值可以是任意文本字符串。
(1)定义数组变量
格式 var[index]=element

#定义数组
capital["Illinois"]="Springfield"
capital["Indiana"] = "Indianapolis"
capital["Ohio"] = "Columbus"
#引用数组
gawk 'BEGIN{capital["Illinois"]="Springfield";print capital["Illinois"]}'
gawk 'BEGIN{var[1]=34;var[2]=3;total=var[1]+var[2];print total}'

(2)遍历数组变量

#gawk中遍历数组的方法
for (var in array)
{
	statements
}
#一个例子:
gawk 'BEGIN{
var["a"]=1
var["g"]=2
var["m"]=3
var["u"]=4
for (test in var)
{
	print "Index:",test,"- value",var[test]
}}'

(3)删除数组变量
delete array[index]

使用模式
(1)正则表达式
匹配了数据字段中含有字符串11的记录
gawk 'BEGIN{FS=","}/11/{print $1}' data1
(2)匹配操作符
~ matching operator
第一个数据字段以文本data开头
$1 ~ /^data/
过滤出第二个数据字段以data2开头的
gawk 'BEGIN{FS=","} $2~/^data2/{print $0}' data1
在/etc/passwd第一个数据字段中查找文本 rich 。如果在记录中找到了这个模式,它会打印该记录的第一个和最后一个数据字段值。
gawk -F: '$1 ~ /rich/{print $1,$NF}’ /etc/passwd
用!排除正则表达式的匹配
$1 !~ /expression/
awk程序脚本会打印/etc/passwd文件中与用户ID rich 不匹配的用户ID和登录shell。
gawk -F: '$1 !~/rich/{print $1,$NF}' /etc/passwd
(3)数学表达式
匹配模式中使用数学表达式
显示所有属于root用户组(组ID=0)的系统用户
gawk -F: '$4 == 0{print $!}' /etc/passwd

数学比较表达式
x == y
x <= y
x < y
x >= y
x > y

对文本数据使用表达式,要注意与正则表达式不同,表达式必须完全匹配
在这里插入图片描述

结构化命令
(1)if语句
格式:

if (condition)
	statement1

可以将它放在一行上,像这样:if (condition) statement1

#有一个文件data4
cat data4
10
5
13
50
34

gawk '{if ($1 > 20) print $1}' data4

如果要在if语句中执行多条语句,就必须用花括号将它们括起来。

gawk '{
if ($1 > 20)
{
	x=$1*2
	print x
}
}' data4
# if-then-else
gawk '{
if ($1 > 20)
{
	x=$1 * 2
	print x
} else
{
	x=$1 / 2
	print x
}}' data4

if-then-else单行命令 if (condition) statement;else statement
gawk '{if ($1 > 2) print $1 * 2;else print $1 /2}'
(2)while语句
格式:

while (condition)
{	
	statement
}

计算一个文件每行值的平均值

gawk '{
total=0
i=1
while (i < 4)
{
	total += $i
	i++
}
avg=total/3
print "average:",avg
}' data5

(3)do-while语句
格式:

do
{
	statements
}while (condition)

读取每条记录的数据字段并将它们加在一起,直到累加结果达到150。

gawk '{
total=0
i=1
do
{
	total += $i
	i++
}while (total < 150)
print total }' data5

(4)for语句
格式:for (variable assignment;condition;iteration process)

gawk '{
total=0
for (i=1;i<4;i++)
{
	total += $i
}
avg= total / 3
print "average=",avg
}' data5

格式化打印
格式:printf "format string",var1,var2...

控制字母描述
c显示ASCII字符
d显示一个整数值
i同上
e用科学计数法显示一个数
f显示一个浮点值
g用科学计数法或者浮点数显示
o显示一个八进制值
s显示一个文本字符串
x显示一个十六进制值
X显示一个十六进制值,但用大写字母A-F
gawk 'BEGIN{
x=10 * 100
printf "The anser is :%e\n",x
}'
The answer is: 1.000000e+03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值