两个有用的shell工具总结

2023-01-04,,,

shell工具之一:sed

sed基础

sed编辑器被称作流编辑器,与常见的交互式文本编辑器刚好相反。文本编辑器可以通过键盘来交互式地插入、删除、替换文本中的数据;而流编辑器是基于一组预先的规则来编辑数据流。

sed命令的格式如下:

sed options script file

选项

说明

-e script

将script中指定的命令添加到运行的命令中

-f file

将file中指定的命令添加到运行的命令中

-n

不为每个命令生成输出,等待print命令来输出

说明:

script用于指定作用在数据量上的单个命令。

如果需要使用多个命令,有两种选择:可以在命令行中使用-e选项指定,不同命令之间用分号隔开;或者使用-f选项在文件中指定。

默认情况下,sed编辑器将指定的命令应用到STDIN输入流上,而不作用于数据源本身,就是说sed不会修改文本文件中的原数据。

1 替换命令substitute

s/pattern/replacement/flags

flags取值如下:

数字:表示replacement将替换每行中第几次出现的pattern

g表示replacement将替换所有出现的pattern

p打印用replacement替换过的行(经常与-n选项搭配使用,-n禁止sed输出,而p会输出修改过的行,二者搭配则仅输出被replacement替换过的行)

w file将替换的结果写到file文件中(只有被替换过的行才会保存到输出文件file中)

[root@benxintuzi shell]# cat data1
benxin benxin benxin benxin benxin
benxin benxin benxin benxin benxin
benxin benxin benxin benxin benxin [root@benxintuzi shell]# sed 's/benxin/tuzi/3' data1
benxin benxin tuzi benxin benxin
benxin benxin tuzi benxin benxin
benxin benxin tuzi benxin benxin [root@benxintuzi shell]# sed 's/benxin/tuzi/g' data1
tuzi tuzi tuzi tuzi tuzi
tuzi tuzi tuzi tuzi tuzi
tuzi tuzi tuzi tuzi tuzi [root@benxintuzi shell]# cat data2
benxin benxin benxin benxin benxin
benxin benxin benxin benxin benxin
benxin benxin benxin benxin benxin
hello hello hello hello hello hello [root@benxintuzi shell]# sed -n 's/benxin/tuzi/p' data2
tuzi benxin benxin benxin benxin
tuzi benxin benxin benxin benxin
tuzi benxin benxin benxin benxin [root@benxintuzi shell]# sed 's/benxin/tuzi/w out' data2
tuzi benxin benxin benxin benxin
tuzi benxin benxin benxin benxin
tuzi benxin benxin benxin benxin
hello hello hello hello hello hello [root@benxintuzi shell]# cat out
tuzi benxin benxin benxin benxin
tuzi benxin benxin benxin benxin
tuzi benxin benxin benxin benxin

2 指定作用行

默认情况下,sed会作用于所有行,如果只想作用于特定行,必须使用行寻址,格式如下:

[address]command或者
address
{
command1
command2
command3
...
}

address可以使用单个行号,或者是起始行号、逗号、结尾行号指定。

[root@benxintuzi shell]# sed '2s/benxin/tuzi/' data1
benxin benxin benxin benxin benxin
tuzi benxin benxin benxin benxin
benxin benxin benxin benxin benxin [root@benxintuzi shell]# sed '2,$s/benxin/tuzi/' data1
benxin benxin benxin benxin benxin
tuzi benxin benxin benxin benxin
tuzi benxin benxin benxin benxin [root@benxintuzi shell]# sed '2,${
s/benxin/tuzi/3
s/hello/world/2
}' data2

benxin benxin benxin benxin benxin
benxin benxin tuzi benxin benxin
benxin benxin tuzi benxin benxin
hello world hello hello hello hello

delete命令会删除指定模式的所有行,如果没有加入行寻址,则会删除流中的所有文本(并不修改原文件)。

3 插入和追加

insert命令i在指定行增加一个新行;

append命令a在指定行增加一个新行。

格式如下:

sed '[address]command\new line'

[root@benxintuzi shell]# cat data1
benxin benxin benxin benxin benxin
benxin benxin benxin benxin benxin
benxin benxin benxin benxin benxin [root@benxintuzi shell]# sed '3i\tuzi tuzi tuzi' data1
benxin benxin benxin benxin benxin
benxin benxin benxin benxin benxin
tuzi tuzi tuzi
benxin benxin benxin benxin benxin [root@benxintuzi shell]# sed '3a\tuzi tuzi tuzi' data1
benxin benxin benxin benxin benxin
benxin benxin benxin benxin benxin
benxin benxin benxin benxin benxin
tuzi tuzi tuzi

4 转换命令transform

转换命令y可以处理单个字符,格式如下:

[address]y/inchars/outchars/

用outchars的第一个字符替换inchars的第一个字符,outchars的第二个字符替换inchars的第二个字符,...,如果inchars和outchars的长度不同,则sed编辑器产生一个错误。

[root@benxintuzi shell]# sed 'y/bn/ti/' data1
teixii teixii teixii teixii teixii
teixii teixii teixii teixii teixii
teixii teixii teixii teixii teixii

5 打印命令

p: 打印文本行

=: 打印行号

l: 打印文本行和不可打印的ASCII字符

[root@benxintuzi shell]# cat data2
benxin benxin benxin benxin benxin
benxin benxin benxin benxin benxin
benxin benxin benxin benxin benxin
hello hello hello hello hello hello [root@benxintuzi shell]# sed -n '2,4p' data2
benxin benxin benxin benxin benxin
benxin benxin benxin benxin benxin
hello hello hello hello hello hello [root@benxintuzi shell]# sed '=' data2

benxin benxin benxin benxin benxin benxin benxin benxin benxin benxin benxin benxin benxin benxin benxin hello hello hello hello hello hello [root@benxintuzi shell]# sed -n '/hello/{
> =
> p
> }' data2
hello hello hello hello hello hello [root@benxintuzi shell]# sed -n 'l' data2
benxin benxin benxin benxin benxin$
benxin benxin benxin benxin benxin$
benxin benxin benxin benxin benxin$
hello hello hello hello hello hello$

6 文件命令

[address]w filename

[address]r filename

[root@benxintuzi shell]# cat data3
This is the line
This is the line
This is the line
This is the line [root@benxintuzi shell]# sed -n '3,4w outfile' data3
[root@benxintuzi shell]# cat
outfile
This is the line
This is the line [root@benxintuzi shell]# sed '1r outfile' data3
This is the line
This is the line
This is the line
This is the line
This is the line
This is the line

sed进阶

1 多行命令

N: 将数据流中的下一行加进来创建一个多行组

D: 删除多行组中的第一行

P: 打印多行组中的第一行

[root@benxintuzi shell]# cat data3
This is the line
This is the line
This is the line
This is the line [root@benxintuzi shell]# sed '/line 2/{N; s/line/number/g}' data3
This is the line
This is the number
This is the number
This is the line

2 跳转命令

[address]b [label]

address决定了哪些行会触发跳转命令;label定义了要跳转的位置,如果没有label参数,那么将跳转到脚本的末尾。定义label:开始,最多可以有7个字符。

[root@benxintuzi shell]# cat data3
This is the line
This is the line
This is the line
This is the line [root@benxintuzi shell]# sed '{2,3b; s/line/number/g}' data3
This is the number
This is the line
This is the line
This is the number [root@benxintuzi shell]# sed '{
2,3b
s/line/number/g
:label
s/the/a/g
}' data3

This is a number
This is the line
This is the line
This is a number

3 测试命令

[address]t [label]

测试命令的跳转不是基于地址,而是基于替换命令是否成功。如下程序每次去除一个逗号,直到一个逗号都没有时结束循环跳转。

[root@benxintuzi shell]# echo "This,is,a,test,to,remove,commas." | sed -n '{
:start
s/,/ /p
t start
}'
This is,a,test,to,remove,commas.
This is a,test,to,remove,commas.
This is a test,to,remove,commas.
This is a test to,remove,commas.
This is a test to remove,commas.
This is a test to remove commas.

4 模式替换

在行The cat sleeps in a hat中,如果想将cat和hat都加上引号,如何做呢?sed中可以使用&表示找到的匹配模式:

[root@benxintuzi shell]# echo "The cat sleeps in a hat" | sed 's/.at/".at"/g'
The ".at" sleeps in a ".at" [root@benxintuzi shell]# echo "The cat sleeps in a hat" | sed 's/.at/"&"/g'
The "cat" sleeps in a "hat"

5 sed实例工具

# 加倍行间距G:$!G表示最后一行不加倍
[root@benxintuzi shell]# cat
data3
This is the line
This is the line
This is the line
This is the line [root@benxintuzi shell]# sed '$!G' data3
This is the line This is the line This is the line This is the line
[root@benxintuzi shell]#
# 行编号工具:
[root@benxintuzi shell]# cat
data3
This is the line
This is the line
This is the line
This is the line [root@benxintuzi shell]# sed '=' data3 | sed 'N; s/\n/\t/'
This is the line
This is the line
This is the line
This is the line
# 删除多余的空白行:
# 关键在于创建一个包含非空白行和一个紧挨空白行的地址区间,匹配该区间则不执行删除。
# /./,/^$/!d,/./表示至少包含一个字符的行,/^$/表示一个空行:
[root@benxintuzi shell]# cat
data4
This is the line This is the line This is the line This is the line [root@benxintuzi shell]# sed '/./,/^$/!d' data4
This is the line This is the line This is the line This is the line
# 删除开头的空行:
[root@benxintuzi shell]# cat
data5 This is the line This is the line This is the line This is the line [root@benxintuzi shell]# sed '/./,$!d' data5
This is the line This is the line This is the line This is the line
# 删除结尾的空行:
[root@benxintuzi shell]# cat
data6
This is the line This is the line This is the line This is the line [root@benxintuzi shell]# sed '{
> :start
> /^\n*$/{$d; N; b start}
> }' data6

This is the line This is the line This is the line This is the line
[root@benxintuzi shell]#

shell工具之二:gawk

gawk基础

gawk程序是unix中原始awk程序的GNU版本。gawk提供了一种编程环境,允许修改和重新组织文件中的数据。格式如下:

gawk options program file

选项

说明

-F fs

指定行中分隔数据字段的分隔符

-f file

指定gawk程序的文件名

-v var=value

定义gawk程序中的一个变量及其默认值

-mf N

指定要处理的数据文件中的最大字段数

-mr N

指定要处理的数据文件中的最大行数

-W keyword

指定gawk的兼容模式或警告等级

gawk程序使用的脚本命令必须放在用单引号括起来的花括号中:

gawk '{print "hello benxintui"}'

gawk在处理文本文件时,自动为行中的每个数据字段分配一个变量:

"$0"表示整行;

"$1"表示行中第1个字段;

"$2"表示行中第2个字段;

...

"$n"表示行中第n个字段。

gawk还可以指定程序何时运行。

在处理数据前运行脚本,可以使用BEGIN关键字:

[root@benxintuzi shell]# cat data3
This is the line
This is the line
This is the line
This is the line [root@benxintuzi shell]# gawk 'BEGIN{print "The data3 File Contents:"} {print $0}' data3
The data3 File Contents:
This is the line
This is the line
This is the line
This is the line

在处理数据后运行脚本,可以使用END关键字:

[root@benxintuzi shell]# gawk 'BEGIN{print "The data3 File Contents:"} {print $0} END{print "End of File"}' data3
The data3 File Contents:
This is the line
This is the line
This is the line
This is the line
End of File

gawk进阶

1 使用变量

内置变量:

1 字段和行分隔变量

变量

说明

FS

输入字段分隔符(默认为空格)

RS

输入行分隔符(默认为换行符)

OFS

输出字段分隔符(默认为空格)

ORS

输出行分隔符(默认为换行符)

[root@benxintuzi shell]# cat data7
This,is,the,line,
This,is,the,line,
This,is,the,line,
This,is,the,line, [root@benxintuzi shell]# gawk 'BEGIN{FS=","; OFS="<-->"; RS="\n"; ORS="|\n"} {print $1,$2,$3,$4,$5}' data7
This<-->is<-->the<-->line<-->|
This<-->is<-->the<-->line<-->|
This<-->is<-->the<-->line<-->|
This<-->is<-->the<-->line<-->| [root@benxintuzi shell]# gawk 'BEGIN{FS=","; OFS="<-->"; RS="\n"; ORS="|\n"} {print $0}' data7
This,is,the,line,|
This,is,the,line,|
This,is,the,line,|
This,is,the,line,|

2 数据变量

变量

说明

ARGC

当前命令行参数个数

ARGV

当前命令行参数数组

ARGIND

当前文件在ARGV中的位置

CONVFMT

数字的转换格式,默认为%.6g

OFMT

数字的输出格式,默认为%.6g

ENVIRON

当前shell环境变量及其值组成的关联数组

ERRNO

错误号

FILENAME

数据文件名

FNR

数据文件中的当前行数

NF

数据文件中每行的字段数

NR

已处理的数据行数(如果同时处理多个文件,则该值会不断累加)

IGNORECASE

当其值非0时,忽略gawk命令中字符串的大小写

RLENGTH

由match匹配的子字符串的长度

RSTART

由match匹配的子字符串的起始位置

[root@benxintuzi shell]# gawk 'BEGIN{print ARGC, ARGV[0], ARGV[1]}' data7
2 gawk data7 [root@benxintuzi shell]# gawk 'BEGIN{print ENVIRON["HOME"]; print ENVIRON["PATH"]}'

/root
/usr/lib/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/java/jdk1..0_75/bin:/usr/java/jdk1..0_75/jre/bin:/bigdata/hadoop-2.6./bin:/bigdata/hadoop-2.6./sbin:/usr/maven/apache-maven-3.3./bin:/home/benxintuzi/bin [root@benxintuzi shell]# gawk '
BEGIN{FS=","}
{print "FILENAME="FILENAME, "ARGIND="ARGIND, "NF="NF", FNR="FNR, "NR="NR}' data7 data7

FILENAME=data7 ARGIND= NF=, FNR= NR=
FILENAME=data7 ARGIND= NF=, FNR= NR=
FILENAME=data7 ARGIND= NF=, FNR= NR=
FILENAME=data7 ARGIND= NF=, FNR= NR=
FILENAME=data7 ARGIND= NF=, FNR= NR=
FILENAME=data7 ARGIND= NF=, FNR= NR=
FILENAME=data7 ARGIND= NF=, FNR= NR=
FILENAME=data7 ARGIND= NF=, FNR= NR=

自定义变量:

gawk变量名区分大小写。

[root@benxintuzi shell]# gawk '
BEGIN{
testing="This is a test"
print testing
testing=45
print testing
}'
This is a test
# 在命令行中给gawk变量赋值:
[root@benxintuzi shell]# cat script1
BEGIN{FS=","}
{print $n}
[root@benxintuzi shell]# gawk -f script1 n=2
data7
is
is
is
is
[root@benxintuzi shell]# gawk -f script1 n=5 data7

2 操作数组

# 数组的定义
[root@benxintuzi shell]# gawk '
> BEGIN{
> capital["China"]="beijing"
> print capital["China"]
> var[1]=20
> var[2]=10
> total=var[1] + var[2]
> print total
> }'
beijing
# 数组的遍历
[root@benxintuzi shell]# gawk '
BEGIN{
var["a"]=1
var["b"]=2
var["c"]=3
for (dex in var)
{
print "Index:" dex " --- " "Value:" var[dex]
}
}'
Index:a --- Value:
Index:b --- Value:
Index:c --- Value: # 数组元素的删除
[root@benxintuzi shell]# gawk '
BEGIN{
var["a"]=1
var["b"]=2
var["c"]=3
for (dex in var)
{
print "Index:" dex " --- " "Value:" var[dex]
}
delete var["b"]
print "-------------------"
for (dex in var)
{
print "Index:" dex " --- " "Value:" var[dex]
}
}'
Index:a --- Value:
Index:b --- Value:
Index:c --- Value:
-------------------
Index:a --- Value:
Index:c --- Value:

3 使用模式

使用正则表达式来匹配时,表达式必须放到作用脚本的花括号左边:

[root@benxintuzi shell]# cat data7
This,is,the,line,
This,is,the,line,
This,is,the,line,
This,is,the,line, [root@benxintuzi shell]# gawk 'BEGIN{FS=","} /,2/{print $0}' data7
This,is,the,line,

使用匹配操作符˜来匹配数据行中的特定字段,如找出以1开头的第二个字段的行,如下所示:

[root@benxintuzi shell]# cat out1
This is a test program
Loop
Loop
Loop
Loop
Loop
Loop
Loop
Loop
Loop
Loop
This is the end of program [root@benxintuzi shell]# gawk '$2 ~ /^1/{print $0}' out1
Loop
Loop

还可以使用比较表达式(== / <= / < / >= / >)来匹配,如显示所有属于root用户组的系统用户(组ID==0):

[root@benxintuzi shell]# cat /etc/passwd
root:x:::root:/root:/bin/bash
bin:x:::bin:/bin:/sbin/nologin
daemon:x:::daemon:/sbin:/sbin/nologin
adm:x:::adm:/var/adm:/sbin/nologin
lp:x:::lp:/var/spool/lpd:/sbin/nologin
sync:x:::sync:/sbin:/bin/sync
shutdown:x:::shutdown:/sbin:/sbin/shutdown
halt:x:::halt:/sbin:/sbin/halt
mail:x:::mail:/var/spool/mail:/sbin/nologin
uucp:x:::uucp:/var/spool/uucp:/sbin/nologin
operator:x:::operator:/root:/sbin/nologin
games:x:::games:/usr/games:/sbin/nologin
gopher:x:::gopher:/var/gopher:/sbin/nologin
ftp:x:::FTP User:/var/ftp:/sbin/nologin
nobody:x:::Nobody:/:/sbin/nologin
dbus:x:::System message bus:/:/sbin/nologin
usbmuxd:x:::usbmuxd user:/:/sbin/nologin
vcsa:x:::virtual console memory owner:/dev:/sbin/nologin
rtkit:x:::RealtimeKit:/proc:/sbin/nologin
avahi-autoipd:x:::Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin
pulse:x:::PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
haldaemon:x:::HAL daemon:/:/sbin/nologin
ntp:x::::/etc/ntp:/sbin/nologin
apache:x:::Apache:/var/www:/sbin/nologin
saslauth:x:::"Saslauthd user":/var/empty/saslauth:/sbin/nologin
postfix:x::::/var/spool/postfix:/sbin/nologin
abrt:x::::/etc/abrt:/sbin/nologin
gdm:x::::/var/lib/gdm:/sbin/nologin
sshd:x:::Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tcpdump:x::::/:/sbin/nologin
benxintuzi:x:::CentOS:/home/benxintuzi:/bin/bash
[root@benxintuzi shell]# gawk -F: '$4 == 0{print $1}' /etc/passwd
root
sync
shutdown
halt
operator

4 结构化命令

if格式:

if (condition)

{

statements

}

else

{

statements

}

if (condition) statements; else statements

while格式:

while (condition)

{

statements

}

do

{

statements

} while (condition)

for格式:

for (assignments; condition; iteration)

5 内置函数

数学函数

说明 (采用弧度为单位)

atan2(x, y)

x/y的反正切

cos(x)

x的余弦值

exp(x)

x的指数函数

int(x)

x的整数部分

rand()

0~1的随机浮点数

sin(x)

x的正弦值

sqrt(x)

x的平方根

srand(x)

种子函数

位操作函数

说明

and(v1, v2)

v1与v2按位与

or(v1, v2)

v1与v2按位或

compl(val)

对val求补

lshift(val, count)

将val左移count位

rshift(val, count)

将val右移count位

xor(v1, v2)

v1与v2按位异或

字符串函数

说明

asort(s [, d])

对数组s按数据元素排序。排序后数组的索引值变为表示顺序的数字。如果指定了d,则将排序后的数组存储到d中

asorti(s [, d])

对数组s按索引值进行排序。排序后数组的元素为表示顺序的索引值。如果指定了d,则将排序后的数组存储到d中

gensub(r, s, h [, t])

查找变量$0或者目标字符串t来匹配正则表达式r。如果h以g/G开头,则用s替换掉匹配的文本;如果h为数字,表示要替换掉第几处匹配的文本

gsub(r, s [, t])

查找变量$0或者目标字符串t来匹配正则表达式r。如果找到了,就全部替换为字符串s

index(s, t)

返回t在s中的索引值。如果没找到,则返回0

length([s])

返回字符串s的长度。如果没有指定s,则返回$0的长度

match(s, r, [, a])

返回字符串s中正则表达式r位置的索引值。如果指定了a,则将s中匹配r的部分存储到a中

split(s, a [, r])

将s用FS字符或者r分隔开存储到a中,返回被分割的行数

sprintf(format, variables)

类似于printf

sub(r, s [, t])

在变量$0或者目标字符串t中查找正则表达式r的匹配,如果找到了,就用s替换掉第一处匹配

substr(s, i [, n])

返回s中从索引值i开始的n个字符构成的字符串。如果未指定n,则返回i开始的所有部分

tolower(s)

将s中的所有字符转换为小写

toupper(s)

将s中的所有字符转换为大写

# 按数组元素排序
[root@benxintuzi shell]# gawk '
BEGIN{
var["d"]=4
var["b"]=3
var["a"]=2
var["c"]=1
asort(var, result)
for (i in result)
print "index:" i " <---> " "value:" result[i]
}'
index: <---> value:
index: <---> value:
index: <---> value:
index: <---> value: # 按数组索引排序
[root@benxintuzi shell]# gawk '
BEGIN{
var["d"]=4
var["b"]=3
var["a"]=2
var["c"]=1
asorti(var, result)
for (i in result)
print "index:" i " <---> " "value:" result[i]
}'
index: <---> value:d
index: <---> value:a
index: <---> value:b
index: <---> value:c [root@benxintuzi shell]# cat data7
This,is,the,line,1
This,is,the,line,2
This,is,the,line,3
This,is,the,line,4
[root@benxintuzi shell]# gawk '
BEGIN{FS=","}
{
number=split($0, var)
print($number, var[1], var[2], var[3], var[4], var[5])
}' data7

This is the line
This is the line
This is the line
This is the line

时间函数

说明

mktime(datespec)

将一个YYYY MM DD HH MM SS [DST]格式的日期转换成时间戳

strftime(format [, timestamp])

将当前时间的时间戳转换为shell函数date()的格式

systime()

返回当前时间的时间戳

[root@benxintuzi shell]# gawk '
> BEGIN{
> date=systime()
> day=strftime("%A %B %d %Y", date)
> print day
> }'
Sunday August

6 自定义函数

格式:

function name ([variables])

{

statements

}

函数的定义必须出现在所有代码块之前,包括BEGIN块。如果将函数放在库文件中定义,则在gawk中使用时,利用-f选项指定库文件。但是如果需要同时通过-f指定脚本文件名,则利用多次-f即可:

# 在命令行中定义函数
[root@benxintuzi shell]# gawk '
function myfunc()
{
print($1, $2, $5)
}
BEGIN{FS=","}
{ myfunc() }' data7

This is
This is
This is
This is # 在库文件中定义函数
[root@benxintuzi shell]# cat funclib
function myfunc()
{
print($1, $2, $5
)
}

[root@benxintuzi shell]# cat script2
BEGIN{FS=","; RS="\n"
}
{
myfunc()
}
[root@benxintuzi shell]# gawk -f funclib -f script2 data7
This is
This is
This is
This is

两个有用的shell工具总结的相关教程结束。

《两个有用的shell工具总结.doc》

下载本文的Word格式文档,以方便收藏与打印。