小言_互联网的博客

Linux:shell脚本进阶(sed/gawk)

378人阅读  评论(0)

目录

sed命令进阶

保持空间和模式空间

Sed进阶篇实例应用

gawk命令进阶


 

#本文章为学习笔记

 

sed命令进阶

1>n命令:移动到下一行

小写n命令会告诉sed编辑器移动到数据流下一行进行处理

 

1.1 n命令原理

n命令简单来说就是提前读取下一行,覆盖模型空间前一行(并没有删除,因此依然打印至标准输出),如果命令未执行成功(并非跳过:前端条件不匹配),则放弃之后的任何命令,并对新读取的内容,重头执行sed。

例子:

从aaa文件中取出偶数行

1

2

3

4

5

6

7

8

9

10

cat aaa 

This is 1    

This is 2    

This is 3    

This is 4    

This is 5    

     

sed -n 'n;p' aaa         //-n表示隐藏默认输出内容    

This is 2    

This is 4


注 释:读取This is 1,执行n命令,此时模式空间为This is 2,执行p,打印模式空间内容This is 2。之后读取 This is 3,执行n命令,此时模式空间为This is 4,执行p,打印模式空间内容This is 4。之后读取This is 5,执行n 命令,因为没有了,所以退出,并放弃p命令。

因此,最终打印出来的就是偶数行。

 

2>N命令:合并文本行

大写N会将下一文本行添加到模式空间中已有的文本后,这样两个文本行合并到同一个模式空间中,文本行仍然用换行符分隔。如果要在文件中查找可能分散在两行中的文本,这个是很实用的功能。

 

2.1 N命令原理:

N命令简单来说就是追加下一行到模式空间,同时将两行看做一行,但是两行之间依然含有\n换行符,如果命令未执行成功(并非跳过:前端条件不匹配),则放弃之后任何命令,并对新读取的内容,重头执行sed。

例子:

从aaa文件中读取奇数行

1

2

3

4

5

6

7

8

9

10

11

cat aaa   

This is 1   

This is 2   

This is 3   

This is 4   

This is 5   

                                                     

sed -n '$!N;P' aaa    #P是只打印第一行(首字母到\n),后面有讲到;       

This is 1   

This is 3   

This is 5

注释中1代表This is 1   2代表This is 2  以此类推

注释:读取This is 1 ,不是尾行,执行N命令,得出1\n2,执行P,打印得This is 1 。读取This is 3,不是尾行,执行N命令,得出3\n4,执行P,打印得This is 3。读取This is 5,是尾行,跳过N(!N),执行P,打印得This is 5。

 

2.2 配置示例


  
  1. 例1
  2. $ cat data2.txt
  3. this is the header line.
  4. this is the first data line.
  5. this is the second data line.
  6. this is the last line.
  7. $ sed '/first/{N;s/\n/ /}' data2.txt
  8. this is the header line.
  9. this is the first data line. this is the second data line.
  10. this is the last line.
  11. 例2
  12. $ cat data3.txt
  13. on Tuesday,the linux system
  14. administrator 's group meeting will be held.
  15. all system administrators should attend.
  16. thank you for your attendance.
  17. $ sed 'N;s/system.administrator/desktop user/ ' data3.txt
  18. on Tuesday,the linux desktop user's group meeting will be held.
  19. all desktop users should attend.
  20. thank you for your attendance.

 

3>只删除前一行的命令,D命令

当有多行匹配出现时,D命令只会删除模式空间中的第一行

 

3.1 D命令工作原理

D命令是删除当前模式空间开端至\n的内容(不在传至标准输出),放弃之后的命令,但是对剩余模式空间重新执行sed。D命令的独特之处在于强制sed编辑器返回到脚本的起始处,对同一模式空间中的内容重新执
行这些命令(它不会从数据流中读取新的文本行)。这个比较特殊,不好理解。

D命令例子

从aaa文件中读取最后一行

1

2

3

4

5

6

7

8

9

cat aaa   

This is 1   

This is 2   

This is 3   

This is 4   

This is 5   

                                                

sed 'N;D' aaa           

This is 5

注释:读取This is 1,执行N,得出This is 1\nThis is 2,执行D,得出This is 2。继续执行N(不是重新读取下一行),得出This is 2\nThis is 3,执行D,得出This is 3。依此类推,得出This is 5,执行N,条件失败退出,因无-n参数(-n只显示匹配处理的行),故输出This is 5。

 

3.2 配置示例


  
  1. $ cat data5.txt
  2. this is the header line.
  3. this is a data line.
  4. this is the last line.
  5. 例1:
  6. $ sed '/^$/{N;/header/D}' data5.txt
  7. this is the header line.
  8. this is a data line.
  9. this is the last line.
  10. 例2:打印最后两行
  11. #思路就是,在执行到倒数第二行时,合并最后一行,并且不删除。最后一行执行动作,结束。
  12. sed '$!N;$!D' data5.txt
  13. this is the last line.

 

4>只打印前一行,P命令

P命令只会打印模式空间中的第一行。


  
  1. $ cat data3.txt
  2. on Tuesday,the linux system
  3. administrator 's group meeting will be held.
  4. all system administrators should attend.
  5. thank you for your attendance.
  6. $ sed -n 'N;/system\nadministrator/P ' data3.txt #使用大写P打印
  7. on Tuesday,the linux system
  8. $ sed -n 'N;/system\nadministrator/p ' data3.txt #使用小写p打印
  9. on Tuesday,the linux system
  10. administrator's group meeting will be held.
  11. $ sed -n 'N;/for/P' data3.txt
  12. all system administrators should attend.

5>排除命令(!)


  
  1. 例1
  2. $ cat data2.txt
  3. this is the header line.
  4. this is the first data line.
  5. this is the second data line.
  6. this is the last line.
  7. $ sed -n '/headeer/!p' data2.txt
  8. this is the first data line.
  9. this is the second data line.
  10. this is the last line.

6>分支。用于改变数据流

格式:[address]b [:label]

address参数决定了哪些行的数据会触发分支命令,label参数定义了要跳转到的位置。


  
  1. 1
  2. $ cat data2.txt
  3. this is the header line.
  4. this is the first data line.
  5. this is the second data line.
  6. this is the last line.
  7. $ sed '{2,3b;s/this is /is this/;s/line./test?/}' data2.txt
  8. is this the header test?
  9. this is the first data line.
  10. this is the second data line.
  11. is this the last test?
  12. 2
  13. $ sed '{/first/b jump1;s/this is the/no jump on/
  14. >:jump1
  15. >s/this is the/jump here on/}' data2.txt
  16. no jump on header line
  17. jump here on first data line
  18. no jump on second data line
  19. no jump on last line
  20. 3
  21. $ sed -n '{
  22. > :start
  23. > s/,//1p
  24. > b start
  25. > }'

 

7>测试(test)命令。用来改变sed编辑器脚本的执行流程,相当于逻辑运算符里面的“或”


  
  1. 例1
  2. $ cat data2.txt
  3. this is the header line.
  4. this is the first data line.
  5. this is the second data line.
  6. this is the last line.
  7. $ sed '{
  8. >s/first/matched/
  9. >t
  10. >s/this is the/no match on/
  11. }' data2.txt
  12. no match on header line
  13. this is the matched data line
  14. no match on second data line
  15. no match on last line
  16. 例2
  17. $ echo "this,is,a,test,to,remove,commas."|sed -n '{
  18. >:start
  19. >s/,/ /1p
  20. >b start
  21. }'
  22. #当无需替换时,测试命令不会跳转而是继续执行剩下的脚本

 

8>替代模式/后向引用(&)

&符号用来代表替换命令中的匹配模式。当要匹配字符串的其中一部分内容时,可用圆括号定义模式中的子模式,用\1、\2等来代表调用子模式。


  
  1. 例1
  2. $ echo 'the cat sleeps in his hat'|sed 's/.at/"&"/g'
  3. the "cat" sleeps in his "hat"
  4. 例2
  5. $ echo 'the system administrator manual'|sed '
  6. >s/\(system\) administrator/\1 user/'
  7. the system user manual
  8. 例3
  9. $ echo '1234567'|sed '{
  10. >:start
  11. >s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/
  12. >t start
  13. >}'
  14. 1,234,567

 

保持空间和模式空间

    模式空间:就是sed编辑器存放待处理文本的缓冲区。sed会每次读取一行文本,并放入模式空间,并执行编辑命令。

    保持空间:临时保存一些行的缓冲区。当模式空间的数据还要再进行处理时(不马上输出),就会用到。

 

有五条命令可用来操作保持空间:

h 将模式空间复制到保持空间(会覆盖)
H 将模式空间追加到保持空间
g 将保持空间复制到模式空间
G 将保持空间追加到模式空间
x 交换模式空间和保持空间的内容


  
  1. 例1
  2. $ cat data2.txt
  3. this is the header line.
  4. this is the first data line.
  5. this is the second data line.
  6. this is the last line.
  7. $ sed -n '{1!G;h;$p}' data2.txt
  8. this is the last line.
  9. this is the second data line.
  10. this is the first data line.
  11. this is the header line.

说明:

第一步:   将第一行(this is the header line.)到模式空间,然后放到保持空间;

第二步:   读取第二行(this is the first data line.)到模式空间,并将保持空间中的(this is the header line.)追加到模式空间,变成(this is the first data line.\nthis is the header line.)。并将(this is the first data line.\nthis is the header line.)放到保持空间中。

第三步:   读取第三行(this is the second data line.)到模式空间,并将保持空间中的(this is the first data line.\nthis is the header line.)追加到模式空间,变成(this is the first data line.\nthis is the header line.\nthis is the second data line.),并放到保持空间中。

第四步:   读取第四行(this is the last line.)到模式空间,并将保持空间中的内容追加到模式空间,最后打印出来。

 

Sed进阶篇实例应用

示例文本:

cat data2.txt
  this is the header line.
  this is the first data line.
  this is the second data line.
  this is the last line.


  
  1. 实例:
  2. 例1:加倍行间距,每行后面加一行空白行;
  3. $ sed 'G' data2.txt
  4. this is the header line.
  5. this is the first data line.
  6. this is the second data line.
  7. this is the last line.
  8. $ sed '$!G' data2.txt #每行后面加一空白行,最后一行不加
  9. this is the header line.
  10. this is the first data line.
  11. this is the second data line.
  12. this is the last line.
  13. $

 


  
  1. 例2:给文件中的行编号;
  2. $ sed '=' data2.txt | sed 'N;s/\n'/ / '
  3. 1 this is the header line.
  4. 2 this is the first data line.
  5. 3 this is the second data line.
  6. 4 this is the last line.
  7. #如果有空白行的话,需要注意先去除空白行

  
  1. 例3:打印末尾10行
  2. $ sed '{
  3. > :start
  4. > $q;N;11,$D
  5. > b start
  6. > }' data7.txt

  
  1. 例4:删除空白行
  2. $ sed '/./,/^$/!d' data8.txt #删除连续空白行;
  3. $ sed '/./,$!d' data9.txt #删除开头n行空白行;
  4. $ sed '{ #删除末尾空白行;
  5. > :start
  6. > /^\n*$/{$d;N;b start}
  7. > }'

 

gawk命令进阶

1>内建变量

FIELDWIDTHS 由空格分隔的一系列数字,定义了每个数据字段的确切宽度
FS 输入字段分隔符,默认是空格符
RS 输入记录分隔符,每行是一条记录,默认是换行符
OFS 输出字段分隔符,默认是空格符
ORS 输出记录分隔符,每行是一条记录,默认是换行符

 

数据变量:

NF 字段总数
NR 已处理的行数
ENVIRON

关联数组组成的shell环境变量值,格式如下

print ENVIRON["HOME"]

   

  
  1. 例1:将逗号分隔符替换为“-”,并输出前三项
  2. $ cat data1
  3. data11,data12,data13,data14,data15
  4. data21,data22,data23,data24,data25
  5. data31,data32,data33,data34,data35
  6. $ gawk 'BEGIN{FS=",";OFS="-"} {print $1,$2,$3}' data1
  7. data11-data12-data13
  8. data21-data22-data23
  9. data31-data32-data33

 


  
  1. 例2:将每行当作一个字段,把空白行当作记录分隔符
  2. $ cat data2
  3. riley mullen
  4. 123 main street
  5. chicago,il 60601
  6. 555-1234
  7. frank williams
  8. 456 oak street
  9. indianapolis , in 46201
  10. 5559876
  11. haley snell
  12. 4231 elm street
  13. detroit,mi 48201
  14. 555-4938
  15. $ gawk 'BEGIN{FS="\n";RS=""} {print $1,$4}' data2
  16. riley mullen 555-1234
  17. frank williams 555-9876
  18. haley snell 555-4938

  
  1. 例3:按固定宽度分隔字段
  2. $ cat data1b
  3. 1005.3247596 .37
  4. 115 -2.349194 .00
  5. 05810.1298100 .1
  6. $ gawk 'BEGIN{FIELDWIDTHS="3 5 2 5"}{print $1,$2,$3,$4}' data1b
  7. 100 5.324 75 96.37
  8. 115 -2.34 91 94.00
  9. 058 10.12 98 100.1

  
  1. 例4:在脚本中使用变量赋值
  2. $ gawk '
  3. > BEGIN{
  4. > testing="this is a test"
  5. > print testing
  6. > testing=46
  7. > print testing
  8. > }'
  9. $ this a testing
  10. $ 45

  
  1. 遍历关联数组
  2. $ gawk 'BEGIN{
  3. > var[a]=1
  4. > var[g]=2
  5. > var[u]=3
  6. > for (test in var)
  7. > {
  8. > print "index:",test," "- Value:",var[test]
  9. > }
  10. > }'
  11. index: u - Value: 3
  12. index: a - Value: 1
  13. index: g - Value: 2
  14. 删除数组元素值:
  15. delete array[index]

  
  1. 匹配限定
  2. $ gawk -F: '$1 ~ /rich/{print $1,$NF}' data1
  3. rich /bin/bash
  4. #这个例子会在第一个数据字段中查找文本rich。如果在记录中找到了这个模式,它会打印
  5. 该记录的第一个和最后一个数据字段值;

  
  1. 数学表达式应用
  2. $ gawk -F: '$4 == 0 {print $1}' /etc/passwd
  3. root
  4. sync
  5. shutdown
  6. halt
  7. operator

  
  1. 结构化命令, if语句
  2. if (condition)
  3. statement1
  4. 也可以将它放在一行上,像这样:
  5. if (condition) statement1
  6. $ gawk '{if ($1 > 20) print $1}' data4
  7. $ gawk '{
  8. > if ($1 > 20)
  9. > {
  10. > x=$1 * 2
  11. > print x
  12. > }
  13. > }' data4
  14. $ gawk '{
  15. > if ($1 > 20)
  16. > {
  17. > x = $1 * 2
  18. > print x
  19. > } else
  20. > {
  21. > x = $1 / 2
  22. > print x
  23. > }}' data4
  24. 可以在单行上使用 else子句,但必须在 if语句部分之后使用分号。
  25. if (condition) statement1; else statement2
  26. 结构化命令, while语句
  27. while (condition)
  28. {
  29. statements
  30. }
  31. $ gawk '{
  32. > total = 0
  33. > i = 1
  34. > while (i < 4)
  35. > {
  36. > total += $i
  37. > i++
  38. > }
  39. > avg = total / 3
  40. > print "Average:",avg
  41. > }' data5
  42. $ gawk '{
  43. > total = 0
  44. > i = 1
  45. > while (i < 4)
  46. > {
  47. > total += $i
  48. > if (i == 2)
  49. > break
  50. > i++
  51. > }
  52. > avg = total / 2
  53. > print "The average of the first two data elements is:",avg
  54. > }' data5
  55. 结构化命令, do-while语句类似于 while语句,但会在检查条件语句之前执行命令。下面是 do-while语
  56. 句的格式。
  57. do
  58. {
  59. statements
  60. } while (condition)
  61. 这种格式保证了语句会在条件被求值之前至少执行一次。当需要在求值条件前执行语句时,
  62. 这个特性非常方便。
  63. $ gawk '{
  64. > total = 0
  65. > i = 1
  66. > do
  67. > {
  68. > total += $i
  69. > i++
  70. > } while (total < 150)
  71. > print total }' data5
  72. for语句是许多编程语言执行循环的常见方法。gawk编程语言支持C风格的 for循环。
  73. for( variable assignment; condition; iteration process)
  74. 将多个功能合并到一个语句有助于简化循环。
  75. $ gawk '{
  76. > total = 0
  77. > for (i = 1; i < 4; i++)
  78. > {
  79. > total += $i
  80. > }
  81. > avg = total / 3
  82. > print "Average:",avg
  83. > }' data5

  
  1. 格式化输出, printf,和c语言用法一样
  2. c 将一个数作为ASCII字符显示
  3. d 显示一个整数值
  4. i 显示一个整数值(跟d一样)
  5. e 用科学计数法显示一个数
  6. f 显示一个浮点值
  7. g 用科学计数法或浮点数显示(选择较短的格式)
  8. o 显示一个八进制值
  9. s 显示一个文本字符串
  10. x 显示一个十六进制值
  11. X 显示一个十六进制值,但用大写字母A~F
  12. 注意,你需要在 printf命令的末尾手动添加换行符来生成新行。没添加的话, printf命令
  13. 会继续在同一行打印后续输出。
  14. printf默认输出是右对齐,可通过“-”来控制成左对齐:
  15. $ gawk 'BEGIN{FS="\n"; RS=""} {printf "%-16s %s\n", $1, $4}' data2
  16. Riley Mullen (312)555-1234
  17. Frank Williams (317)555-9876
  18. Haley Snell (313)555-4938
  19. $
  20. 处理浮点数:
  21. $ gawk '{
  22. > total = 0
  23. > for (i = 1; i < 4; i++)
  24. > {
  25. > total += $i
  26. > }
  27. > avg = total / 3
  28. > printf "Average: %5.1f\n",avg
  29. > }' data5
  30. Average: 128.3
  31. Average: 137.7
  32. Average: 176.7
  33. $

  
  1. #打印test.txt的第3行至第5行
  2. awk 'NR==3,NR==5 {print}' test.txt
  3. #打印test.txt的第3行至第5行的第一列与最后一列
  4. awk 'NR==3,NR==5 {print $1,$NF}' test.txt
  5. #打印test.txt中长度大于80的行号
  6. awk 'length($0)>80 {print NR}' test.txt
  7. #计算test.txt中第一列的总和
  8. cat test.txt|awk '{sum+=$1}END{print sum}'
  9. #添加自定义字符
  10. ifconfig eth0|grep 'Bcast'|awk '{print "ip_" $2}'
  11. #格式化输出
  12. awk -F: '{printf "% -12s % -6s % -8s\n",$1,$2,$NF}' /etc/passwd

 

注:本章内容为读书笔记,摘自《Linux命令行与shell脚本编程大全》第3版。


转载:https://blog.csdn.net/qq_35229961/article/details/90693541
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场