本文相关的两个示例文件:

  • sname
Sr.No Name
11 Vivek
12 Renuka
13 Prakash
14 Ashish
15 Rani
  • smark
Sr.No Mark
11 67
12 55
13 96
14 36
15 67

cut

功能: 从文件或者标准输入中读取内容并截取每一行的特定部分并送到标准输出。

用法

1
cut -f{field number} {file-name}

示例

1
2
3
4
5
6
$cut -f2 sname
Vivek
Renuka
Prakash
Ashish
Rani

paste

功能: 用于按列合并文件。

用法

1
paste {file1} {file2}

示例

1
2
3
4
5
6
$ paste sname smark
11 Vivek 11 67
12 Renuka 12 55
13 Prakash 13 96
14 Ashish 14 36
15 Rani 15 67

join

功能: 根据指定栏位连接两个文件。

用法

1
join {file1} {file2}

示例

1
2
3
4
5
6
$join sname smark
11 Vivek 67
12 Renuka 55
13 Prakash 96
14 Ashish 36
15 Rani 67

tr

功能: 转换字符。

用法

1
tr {pattern-1} {pattern-2}

示例

示例1

1
2
3
4
5
6
$ tr "h2" "3x" < sname
11 Vivek
1x Renuka
13 Prakas3
14 As3is3
15 Rani

示例2

1
2
3
4
5
$ tr "[a-z]" "[A-Z]"
hi i am Vivek
HI I AM VIVEK
what a magic
WHAT A MAGIC

sed

功能: 编辑文件,而无需借助编辑器。

用法

1
2
sed option 'script' file1 file2 ...
sed option -f scriptfile file1 file2 ...

sed处理的文件既可以由标准输入重定向得到,也可以当命令行参数传入,命令行参数可以一次传入多个文件,sed会依次处理。sed的编辑命令可以直接当命令行参数传入,也可以写成一个脚本文件然后用-f参数指定,编辑命令的格式为:

1
/pattern/action

其中pattern是正则表达式,action是编辑操作。sed程序一行一行读出待处理文件,如果某一行与pattern匹配,则执行相应的action。如果一条命令没有pattern而只有action,这个action将作用于待处理文件的每一行

注意,sed命令不会修改原文件。要使得 sed 的结果保存到文件中,可以借助重定向命令将标准输出重定向到文件。

常用 sed 命令

/pattern/p 打印匹配pattern的行
/pattern/d 删除匹配pattern的行
/pattern/s/pattern1/pattern2/ 查找符合pattern的行,将该行第一个匹配pattern1的字符串替换为pattern2
/pattern/s/pattern1/pattern2/g 查找符合pattern的行,将该行所有匹配pattern1的字符串替换为pattern2

示例

p命令

使用p命令需要注意,sed是把待处理文件的内容连同处理结果一起输出到标准输出的,因此 p命令表示除了把文件内容打印出来之外还额外打印一遍匹配pattern的行 。要想只输出处理结果,应加上-n选项,这种用法相当于grep命令

1
2
$ sed -n '/abc/p' testfile
abc

d命令

使用d命令就不需要-n参数了,比如删除含有abc的行

1
2
3
$ sed '/abc/d' testfile
123
456

s命令

当前目录有一文件 teaormilk:

1
2
3
India's milk is good.
tea Red-Lable is good.
tea is better than the coffee.

之后

1
2
3
4
5
$ sed '/tea/s//milk/g' teaormilk > /tmp/result.tmp.$$
$ cat /tmp/result.tmp.$$
India's milk is good.
milk Red-Lable is good.
milk is better than the coffee.

使用查找替换命令时,可以把匹配pattern1的字符串复制到pattern2中,比如:

1
2
3
4
$ sed 's/bc/-&-/' testfile
123
a-bc-
456

pattern2中的&表示原文件的当前行中与pattern1相匹配的字符串,再比如:

1
2
3
4
$ sed 's/\([0-9]\)\([0-9]\)/-\1-~\2~/' testfile
-1-~2~3
abc
-4-~5~6

pattern2中的\1表示与pattern1的第一个()括号相匹配的内容,\2表示与pattern1的第二个()括号相匹配的内容。sed默认使用Basic正则表达式规范,如果指定了-r选项则使用Extended规范,那么()括号就不必转义了。

如果testfile的内容是

1
2
<html><head><title>Hello World</title>
<body>Welcome to the world of regexp!</body></html>

grep 是贪心的

现在要去掉所有的HTML标签,使输出结果为

1
2
Hello World
Welcome to the world of regexp!

怎么做呢?如果用下面的命令

1
$ sed 's/<.*>//g' testfile

结果是两个空行,把所有字符都过滤掉了。这是因为,正则表达式中的数量限定符会匹配尽可能长的字符串,这称为贪心的(Greedy)[^1:有些正则表达式规范支持Non-greedy的数量限定符,匹配尽可能短的字符串,例如在Python中*?*一样表示0个或任意多个,但前者是Non-greedy的]。比如sed在处理第一行时,<.*>匹配的并不是<html><head>这样的标签,而是

1
<html><head><title>Hello World</title>

这样一整行,因为这一行开头是<,中间是若干个任意字符,末尾是>。对于 sed 中的贪婪性问题,暂时没有一个通用的解决办法。

awk

功能: 数据操纵。sed以行为单位处理文件,awk比sed强的地方在于不仅能以行为单位还能以列为单位处理文件。

用法

awk实际上是一门很复杂的脚本语言,还有像C语言一样的分支和循环结构,但是基本用法和sed类似,awk命令行的基本形式为:

1
2
awk option 'script' file1 file2 ...
awk option -f scriptfile file1 file2 ...

awk缺省的行分隔符是换行,缺省的列分隔符是连续的空格和Tab,但是行分隔符和列分隔符都可以自定义,比如/etc/passwd文件的每一行有若干个字段,字段之间以:分隔,就可以重新定义awk的列分隔符为:并以列为单位处理这个文件。

和sed一样,awk处理的文件既可以由标准输入重定向得到,也可以当命令行参数传入,编辑命令可以直接当命令行参数传入,也可以用-f参数指定一个脚本文件。

编辑命令的格式为:

1
2
/pattern/{actions}
condition{actions}

和sed类似,pattern是正则表达式,actions是一系列操作。awk程序一行一行读出待处理文件,如果某一行与pattern匹配,或者满足condition条件,则执行相应的actions,如果一条awk命令只有actions部分,则actions作用于待处理文件的每一行。

pattern + action

若当前目录有一文件 inventory:

egg order 4
cacke good 10
cheese okay 4
pen good 12
floppy good 5

之后

1
2
3
4
$ awk '/good/ { print $3 }' inventory
10
12
5

其中,自动变量 $3 表示第三列,类似的$1$2分别表示第一列、第二列等,而$0表示整个当前行。print 命令用来打印 awk 的变量或者用双引号括起来的文本。

condition + action

再比如,如果某种产品的库存量低于75则在行末标注需要订货:

1
2
3
4
$ awk '$2<75 {printf "%s\t%s\n", $0, "REORDER";} $2>=75 {print $0;}' testfile
ProductA 30 REORDER
ProductB 76
ProductC 55 REORDER

可见awk也有和C语言非常相似的printf函数。

awk 常用的内建变量

awk命令有一些内建变量。

变量名 用途
FILENAME 当前输入文件的文件名,该变量是只读的
NR 当前行的行号,该变量是只读的,R代表record
NF 当前行所拥有的列数,该变量是只读的,F代表field
OFS 输出格式的列分隔符,缺省是空格
FS 输入文件的列分融符,缺省是连续的空格和Tab
ORS 输出格式的行分隔符,缺省是换行符
RS 输入文件的行分隔符,缺省是换行符

除此之外,用户也可可以像C语言一样使用自定义变量。例如:

1
$ awk '/^ *$/ {x=x+1;} END {print x;}' testfile

数学运算

awk还可以进行一些简单的数学计算:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ cat > math
{
print $1 " + " $2 " = " $1 + $2
print $1 " - " $2 " = " $1 - $2
print $1 " / " $2 " = " $1 / $2
print $1 " x " $2 " = " $1 * $2
print $1 " mod " $2 " = " $1 % $2
}
$ awk -f math
20 3
20 + 3 = 23
20 - 3 = 17
20 / 3 = 6.66667
20 x 3 = 60
20 mod 3 = 2
(Press CTRL + D to terminate)

BEGIN…END

awk命令的condition部分还可以是两个特殊的condition-BEGINEND,对于每个待处理文件,BEGIN后面的actions在处理整个文件之前执行一次,END后面的actions在整个文件处理完之后执行一次。

计算下面数据每个同学的平均分
王一 90
赵二 95
刘三 80
陈四 70

1
2
$ awk '{x=x+$2; y=y+1} END {print "total: " x/y }' test
total: 83.75

一个更复杂的例子

iven 文件:

Sr.No Product Qty Unit Price
1 Pen 5 20.00
2 Rubber 10 2.00
3 Pencil 3 3.50
4 Cock 2 45.50

编写脚本计算总价:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
$ cat > bill2
BEGIN {
print "---------------------------"
print "Bill for the 4-March-2001. "
print "By Vivek G Gite. "
print "---------------------------"
}
{
total = $3 * $4
recno = $1
item = $2
gtotal += total
print recno item " Rs." total
}
END {
print "---------------------------"
print "Total Rs." gtotal
print "==========================="
}
$awk -f bill2 inven
---------------------------
Bill for the 4-March-2001.
By Vivek G Gite.
---------------------------
1.Pen Rs.100
2.Pencil Rs.20
3.Rubber Rs.10.5
4.Cock Rs.91
---------------------------
Total Rs.221.5
===============

条件判断

除了利用 condition ,awk 还支持更高级的条件判断:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if ( condition )
{
Statement 1
Statement 2
Statement N
if condition is TRUE
}
else
{
Statement 1
Statement 2
Statement N
if condition is FALSE
}

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
$ awk > math2
BEGIN {
myprompt = "(To Stop press CTRL+D) > "
printf "Welcome to MyAddtion calculation awk program v0.1\n"
printf "%s" ,myprompt
}
{
no1 = $1
op = $2
no2 = $3
ans = 0
if ( op == "+" )
{
ans = $1 + $3
printf "%d %c %d = %d\n" ,no1,op,no2,ans
printf "%s" ,myprompt
}
else
{
printf "Opps!Error I only know how to add.\nSyntax: number1 + number2\n"
printf "%s" ,myprompt
}
}
END {
printf "\nGoodbuy %s\n" , ENVIRON["USER"]
}
$awk -f math2
Welcome to MyAddtion calculation awk program v0.1
(To Stop press CTRL+D) > 5 + 2
5 + 2 = 7
(To Stop press CTRL+D) > 3 - 1
Opps!Error I only know how to add.
Syntax: number1 + number2
(To Stop press CTRL+D) >
Goodbuy vivek

循环

awk 也支持循环语句。

for 循环

1
2
3
4
5
6
for (expr1; condition; expr2)
{
Statement 1
Statement 2
Statement N
}

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ cat > while01.awk
BEGIN{
printf "Press ENTER to continue with for loop example from LSST v1.05r3\n"
}
{
sum = 0
i = 1
for (i=1; i<=10; i++)
{
sum += i; # sum = sum + i
}
printf "Sum for 1 to 10 numbers = %d \nGoodbuy!\n\n", sum
exit 1
}
$ awk -f while01.awk
Press ENTER to continue with for loop example from LSST v1.05r3
Sum for 1 to 10 numbers = 55
Goodbuy

while 循环

1
2
3
4
5
6
7
while (condition)
{
statement1
statement2
statementN
Continue as long as given condition is TRUE
}

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ cat > while_loop
{
no = $1
remn = 0
while ( no > 1 )
{
remn = no % 10
no /= 10
printf "%d" ,remn
}
printf "\nNext number please (CTRL+D to stop):";
}
$awk -f while_loop
654
456
Next number please(CTRL+D to stop):587
785
Next number please(CTRL+D to stop):

uniq

功能: 移除冗余的行。

用法

1
uniq {file-name}

示例

当前目录有一文件 personame :

1
2
3
4
5
6
7
8
9
Hello I am vivek
12333
12333
welcome
to
sai computer academy, a'bad.
what still I remeber that name.
oaky! how are u luser?
what still I remeber that name.

之后

1
2
3
4
5
6
7
8
9
$ uniq personame
Hello I am vivek
12333
welcome
to
sai computer academy, a'bad.
what still I remeber that name.
oaky! how are u luser?
what still I remeber that name.

可以看到原来相邻的两句 12333 在调用 uniq 命令之后只剩下一句,而相同的两句 what still I remeber that name. 因为没有相邻,所以 ‘uniq’ 命令认为它们不冗余,因而没有删除其中一句。如果需要删除即使不相邻的重复句子,可以结合 sort 命令:

1
$ sort personame | uniq

grep

功能: 根据匹配规则过滤文件内容。

用法

1
grep "word-to-find" {file-name}

示例

当前目录有一文件 demo-file :

1
2
3
4
5
6
7
8
hello world!
cartoons are good
especially toon like tom (cat)
what
the number one song
12221
they love us
I too

之后

1
2
3
4
$ grep "too" demofile
cartoons are good
especially toon like tom (cat)
I too

egrep

grep的正则表达式有Basic和Extended两种规范。egrep相当于grep -E,表示采用Extended正则表达式语法

fgrep

另外还有fgrep命令,相当于grep -F,表示只搜索固定字符串而不搜索正则表达式模式,不会按正则表达式的语法解释后面的参数。

深入阅读

  1. awk - Revisited

Comments