对于行处理的工具,sed绝对是首选的。
sed处理文本过程如下:

 

  1. sed一次处理一行内容,处理时,先读入一行,去掉尾部换行符,存入pattern space,执行编辑命令.  
  2. 处理完毕,除非加了-n参数,把现在的pattern space打印出来,在后边打印曾去掉的换行符.  
  3. 把pattern space内容给hold space,把pattern space置空,接着读下一行,处理下一行. 

这让人感觉很抽象,sedsed的工具就是为了展现sed处理过程的。sedsed安装和使用都很简单,为了更好理解sed,装上sedsed工具是很有必要的。

  1. wget http://aurelio.net/sedsed/sedsed-1.0   
  2. touch /usr/local/bin/sedsed   
  3. cat sedsed-1.0 >> /usr/local/bin/sedsed   
  4. chmod 755 /usr/local/bin/sedsed 

用法如下

  1. usage: sedsed OPTION [-e sedscript] [-f sedscriptfile] [inputfile]  
  2. OPTIONS:  
  3.  
  4.      -f, --file          add file contents to the commands to be parsed  
  5.      -e, --expression    add the script to the commands to be parsed  
  6.      -n, --quiet         suppress automatic printing of pattern space  
  7.          --silent        alias to --quiet  
  8.  
  9.      -d, --debug         debug the sed script  
  10.          --hide          hide some debug info (options: PATT,HOLD,COMM)  
  11.          --color         shows debug output in colors (default: ON)  
  12.          --nocolor       no colors on debug output  
  13.          --dump-debug    dumps to screen the debugged sed script  
  14.  
  15.          --emu           emulates GNU sed (INCOMPLETE)  
  16.          --emudebug      emulates GNU sed debugging the sed script (INCOMPLETE)  
  17.  
  18.      -i, --indent        script beautifier, prints indented and  
  19.                          one-command-per-line output do STDOUT  
  20.          --prefix        indent prefix string (default: 4 spaces)  
  21.  
  22.      -t, --tokenize      script tokenizer, prints extensive  
  23.                          command by command information  
  24.      -H, --htmlize       converts sed script to a colorful HTML page  
  25.        
  26. -f选项和sed的-f选项一样  
  27. -d打开debug,其中--hide表示隐藏指定的内容;如--hide=hold表示隐藏的保留空间缓冲区的内容  
  28. -i 的--indent 格式化复杂的sed脚本变成更加人性化的脚本 

先看个简单的例子:
[root@localhost ~]# cat 1.txt
linux
centos
redhat
linux
ubuntu
fedora
把linux换成debian,下面给出三种处理方式:sed处理;sedsed -d 和sedsed -d --hide

  1. [root@localhost ~]# sed 's/linux/debian/g' 1.txt   
  2. debian  
  3. centos  
  4. redhat  
  5. debian  
  6. ubuntu  
  7. fedora  
  8. [root@localhost ~]# sedsed -d  's/linux/debian/g' 1.txt   
  9. PATT:linux$  
  10. HOLD:$  
  11. COMM:s/linux/debian/g  
  12. PATT:debian$  
  13. HOLD:$  
  14. debian  
  15. PATT:centos$  
  16. HOLD:$  
  17. COMM:s/linux/debian/g  
  18. PATT:centos$  
  19. HOLD:$  
  20. centos  
  21. PATT:redhat$  
  22. HOLD:$  
  23. COMM:s/linux/debian/g  
  24. PATT:redhat$  
  25. HOLD:$  
  26. redhat  
  27. PATT:linux$  
  28. HOLD:$  
  29. COMM:s/linux/debian/g  
  30. PATT:debian$  
  31. HOLD:$  
  32. debian  
  33. PATT:ubuntu$  
  34. HOLD:$  
  35. COMM:s/linux/debian/g  
  36. PATT:ubuntu$  
  37. HOLD:$  
  38. ubuntu  
  39. PATT:fedora$  
  40. HOLD:$  
  41. COMM:s/linux/debian/g  
  42. PATT:fedora$  
  43. HOLD:$  
  44. fedora  
  45. [root@localhost ~]# sedsed -d  --hide=hold 's/linux/debian/g' 1.txt   
  46. PATT:linux$  
  47. COMM:s/linux/debian/g  
  48. PATT:debian$  
  49. debian  
  50. PATT:centos$  
  51. COMM:s/linux/debian/g  
  52. PATT:centos$  
  53. centos  
  54. PATT:redhat$  
  55. COMM:s/linux/debian/g  
  56. PATT:redhat$  
  57. redhat  
  58. PATT:linux$  
  59. COMM:s/linux/debian/g  
  60. PATT:debian$  
  61. debian  
  62. PATT:ubuntu$  
  63. COMM:s/linux/debian/g  
  64. PATT:ubuntu$  
  65. ubuntu  
  66. PATT:fedora$  
  67. COMM:s/linux/debian/g  
  68. PATT:fedora$  
  69. fedora 

其中:
PATT:sedsed输出显示模式空间缓冲区的内容
COMM:显示正在执行的命令
HOLD:显示hold sapce缓冲区的内容

sed的增删改查
sed用于删除操作的是:d和D
命令"d"作用是删除模式空间的内容,然后读入新的行,sed脚本从头再次开始执行.
命令"D"的不同之处在于它删除的是直到第一个内嵌换行符为止的模式空间的一部分,但是不会读入新的行,脚本将回到开始对剩下内容进行处理. 
看个例子

  1. [root@localhost ~]# cat 2.txt   
  2. This line is followed by 1 blank line.  
  3.  
  4. This line is followed by 2 blank line.  
  5.  
  6.  
  7. This line is followed by 3 blank line.  
  8.  
  9.  
  10.  
  11. This line is followed by 4 blank line.  
  12.  
  13.  
  14.  
  15.  
  16. This is the end. 
  1. [root@localhost ~]# sed '/^$/{N;/^\n$/D}' 2.txt   
  2. This line is followed by 1 blank line.  
  3.  
  4. This line is followed by 2 blank line.  
  5.  
  6. This line is followed by 3 blank line.  
  7.  
  8. This line is followed by 4 blank line.  
  9.  
  10. This is the end.  
  11. [root@localhost ~]# sed '/^$/{N;/^\n$/d}' 2.txt   
  12. This line is followed by 1 blank line.  
  13.  
  14. This line is followed by 2 blank line.  
  15. This line is followed by 3 blank line.  
  16.  
  17. This line is followed by 4 blank line.  
  18. This is the end. 

用sedsed 打开debug看看执行过程 //后面的内容是我注释的

  1. [root@localhost ~]# sedsed -d  '/^$/{N;/^\n$/D}' 2.txt   
  2. PATT:This line is followed by 1 blank line.$  //pattern空间读入第一行内容  
  3. HOLD:$                                        //hold空间开始为空  
  4. COMM:/^$/ {            //正在执行的命令,判断是否为空行,很明显不是,所有不执行后面的命令,执行的结果送往屏幕并把结果给hold space.  
  5. PATT:This line is followed by 1 blank line.$  
  6. HOLD:$  
  7. This line is followed by 1 blank line.  
  8. PATT:$                //pattern空间读入第二行  
  9. HOLD:$                //hold空间开始还是为空  
  10. COMM:/^$/ {           //正在执行的命令,判断是否为空行,很明显是,所有执行后面的命令  
  11. COMM:N                //执行N读取下一行进入pattern空间  
  12. PATT:\nThis line is followed by 2 blank line.$  
  13. HOLD:$               //此时hold空间还是为空  
  14. COMM:/^\n$/ D        //对pattern空间继续执行后面的命令:如果是空行,执行D命令,很明显不是,所有不执行。  
  15. PATT:\nThis line is followed by 2 blank line.$  //pattern空间内容  
  16. HOLD:$              //hold空间内容,任然为空。  
  17. COMM:}  
  18. PATT:\nThis line is followed by 2 blank line.$  
  19. HOLD:$  
  20.  
  21. This line is followed by 2 blank line.  //由于没有满足执行条件,继续读取下一行。  
  22. PATT:$           //空行,满足执行条件,执行命令  
  23. HOLD:$  
  24. COMM:/^$/ {      
  25. COMM:N  
  26. PATT:\n$  
  27. HOLD:$  
  28. COMM:/^\n$/ D    //满足执行D命令条件,删除一空行(现在有两空行)  
  29. PATT:$  
  30. HOLD:$  
  31. COMM:/^$/ {  
  32. COMM:N  
  33. PATT:\nThis line is followed by 3 blank line.$  
  34. HOLD:$  
  35. COMM:/^\n$/ D  
  36. PATT:\nThis line is followed by 3 blank line.$  
  37. HOLD:$  
  38. COMM:}  
  39. PATT:\nThis line is followed by 3 blank line.$  
  40. HOLD:$  
  41.  
  42. This line is followed by 3 blank line.  
  43. PATT:$         \\空行,满足命令执行条件,执行命令,读取下一行.  
  44. HOLD:$  
  45. COMM:/^$/ {  
  46. COMM:N  
  47. PATT:\n$  
  48. HOLD:$  
  49. COMM:/^\n$/ D  \\满足执行D命令,删除一空行.  
  50. PATT:$         \\空行,满足命令执行条件,执行命令,读取下一行.  
  51. HOLD:$  
  52. COMM:/^$/ {  
  53. COMM:N  
  54. PATT:\n$  
  55. HOLD:$  
  56. COMM:/^\n$/ D  \\ \\满足执行D命令,删除一空行.  
  57. PATT:$  
  58. HOLD:$  
  59. COMM:/^$/ {  
  60. COMM:N  
  61. PATT:\nThis line is followed by 4 blank line.$  
  62. HOLD:$  
  63. COMM:/^\n$/ D  
  64. PATT:\nThis line is followed by 4 blank line.$  
  65. HOLD:$  
  66. COMM:}  
  67. PATT:\nThis line is followed by 4 blank line.$  
  68. HOLD:$  
  69.  
  70. This line is followed by 4 blank line.  
  71. PATT:$  
  72. HOLD:$  
  73. COMM:/^$/ {  
  74. COMM:N  
  75. PATT:\n$  
  76. HOLD:$  
  77. COMM:/^\n$/ D  
  78. PATT:$  
  79. HOLD:$  
  80. COMM:/^$/ {  
  81. COMM:N  
  82. PATT:\n$  
  83. HOLD:$  
  84. COMM:/^\n$/ D  
  85. PATT:$  
  86. HOLD:$  
  87. COMM:/^$/ {  
  88. COMM:N  
  89. PATT:\n$  
  90. HOLD:$  
  91. COMM:/^\n$/ D  
  92. PATT:$  
  93. HOLD:$  
  94. COMM:/^$/ {  
  95. COMM:N  
  96. PATT:\nThis is the end.$  
  97. HOLD:$  
  98. COMM:/^\n$/ D  
  99. PATT:\nThis is the end.$  
  100. HOLD:$  
  101. COMM:}  
  102. PATT:\nThis is the end.$  
  103. HOLD:$  
  104.  
  105. This is the end.  
  106.  
  107. [root@localhost ~]# sedsed -d  '/^$/{N;/^\n$/d}' 2.txt   
  108. PATT:This line is followed by 1 blank line.$  
  109. HOLD:$  
  110. COMM:/^$/ {  
  111. PATT:This line is followed by 1 blank line.$  
  112. HOLD:$  
  113. This line is followed by 1 blank line.  
  114. PATT:$  
  115. HOLD:$  
  116. COMM:/^$/ {  
  117. COMM:N  
  118. PATT:\nThis line is followed by 2 blank line.$  
  119. HOLD:$  
  120. COMM:/^\n$/ d  
  121. PATT:\nThis line is followed by 2 blank line.$  
  122. HOLD:$  
  123. COMM:}  
  124. PATT:\nThis line is followed by 2 blank line.$  
  125. HOLD:$  
  126.  
  127. This line is followed by 2 blank line.  
  128. PATT:$          \\空行,满足命令执行条件,执行命令,读取下一行.  
  129. HOLD:$  
  130. COMM:/^$/ {  
  131. COMM:N  
  132. PATT:\n$  
  133. HOLD:$  
  134. COMM:/^\n$/ d   \\满足执行d命令条件,此时模式空间的两个空行都被删除.  
  135. PATT:This line is followed by 3 blank line.$  
  136. HOLD:$  
  137. COMM:/^$/ {  
  138. PATT:This line is followed by 3 blank line.$  
  139. HOLD:$  
  140. This line is followed by 3 blank line.  
  141. PATT:$  
  142. HOLD:$  
  143. COMM:/^$/ {  
  144. COMM:N  
  145. PATT:\n$  
  146. HOLD:$  
  147. COMM:/^\n$/ d  
  148. PATT:$  
  149. HOLD:$  
  150. COMM:/^$/ {  
  151. COMM:N  
  152. PATT:\nThis line is followed by 4 blank line.$  
  153. HOLD:$  
  154. COMM:/^\n$/ d  
  155. PATT:\nThis line is followed by 4 blank line.$  
  156. HOLD:$  
  157. COMM:}  
  158. PATT:\nThis line is followed by 4 blank line.$  
  159. HOLD:$  
  160.  
  161. This line is followed by 4 blank line.  
  162. PATT:$  
  163. HOLD:$  
  164. COMM:/^$/ {  
  165. COMM:N  
  166. PATT:\n$  
  167. HOLD:$  
  168. COMM:/^\n$/ d  
  169. PATT:$  
  170. HOLD:$  
  171. COMM:/^$/ {  
  172. COMM:N  
  173. PATT:\n$  
  174. HOLD:$  
  175. COMM:/^\n$/ d  
  176. PATT:This is the end.$  
  177. HOLD:$  
  178. COMM:/^$/ {  
  179. PATT:This is the end.$  
  180. HOLD:$  
  181. This is the end. 

一般情况下,都用d来删除,如:

  1. 删除空行:  
  2. sed '/^\s*$/d' filename  
  3. sed '/^[[:space:]]*$/d' filename   
  4. 用行标示号来删除  
  5. sed  'n1d'  filename   删除第n1行  
  6. sed 'n1,n2d' filename  删除第n1行到n2行间内容(n1<=n2)  
  7. sed  '5,$d' filename   删除第5行以后内容内容  
  8. 用特殊匹配来删除,格式如下  
  9. sed '/regular_pattern/d' filename 

sed基于行的插入和替换操作是由:a\,i\,c\来完成

  1. a\命令是追加命令,追加将添加新文本到文件中当前行(即读入模式缓冲区中的行)的后面.所追加的文本行位于sed命令的下方另起一行.如果要追加的内容超过一行,则每一行都必须以反斜线结束,最后一行除外.最后一行将以引号和文件名结束.  
  2. i\ 命令是在当前行的前面插入新的文本.  
  3. c\ 用新的文本改变本行的文本 

a\和i\用法比较简单,看一个c\的例子

  1. [root@localhost ~]# cat 1.txt   
  2. linux  
  3. centos  
  4. redhat  
  5. linux  
  6. ubuntu linux  
  7. fedora  
  8. [root@localhost ~]# sedsed -d '/linux/c\unix' 1.txt   
  9. PATT:linux$  
  10. HOLD:$  
  11. COMM:/linux/ c\\N\unix  
  12. unix  
  13. PATT:centos$  
  14. HOLD:$  
  15. COMM:/linux/ c\\N\unix  
  16. PATT:centos$  
  17. HOLD:$  
  18. centos  
  19. PATT:redhat$  
  20. HOLD:$  
  21. COMM:/linux/ c\\N\unix  
  22. PATT:redhat$  
  23. HOLD:$  
  24. redhat  
  25. PATT:linux$  
  26. HOLD:$  
  27. COMM:/linux/ c\\N\unix  
  28. unix  
  29. PATT:ubuntu linux$  
  30. HOLD:$  
  31. COMM:/linux/ c\\N\unix  
  32. unix  
  33. PATT:fedora$  
  34. HOLD:$  
  35. COMM:/linux/ c\\N\unix  
  36. PATT:fedora$  
  37. HOLD:$  
  38. fedora 

sed的替换操作是用的最多的,用sed处理内容,最重要的就是要找特征数据(字符),并以此为基础处理内容而不会处理的内容过多或者处理不完全.
如最开始的举的把linux换成debian的例子.

sed 的高级运用
打印匹配行号

  1. [root@localhost ~]# cat 1.txt   
  2. linux  
  3. centos  
  4. redhat  
  5. linux  
  6. ubuntu linux  
  7. fedora  
  8. [root@localhost ~]# sed -n '/^linux/=' 1.txt  
  9. 1  
  10. 4  
  11. [root@localhost ~]# sed -n '/^linux/{=;p}' 1.txt  
  12. 1  
  13. linux  
  14. 4  
  15. linux  
  16. [root@localhost ~]# sedsed -d  -n  '/^linux/{=;p}' 1.txt  
  17. PATT:linux$  
  18. HOLD:$  
  19. COMM:/^linux/ {  
  20. COMM:=  
  21. 1 
  22. PATT:linux$  
  23. HOLD:$  
  24. COMM:p  
  25. linux  
  26. PATT:linux$  
  27. HOLD:$  
  28. COMM:}  
  29. PATT:linux$  
  30. HOLD:$  
  31. PATT:centos$  
  32. HOLD:$  
  33. COMM:/^linux/ {  
  34. PATT:centos$  
  35. HOLD:$  
  36. PATT:redhat$  
  37. HOLD:$  
  38. COMM:/^linux/ {  
  39. PATT:redhat$  
  40. HOLD:$  
  41. PATT:linux$  
  42. HOLD:$  
  43. COMM:/^linux/ {  
  44. COMM:=  
  45. 4 
  46. PATT:linux$  
  47. HOLD:$  
  48. COMM:p  
  49. linux  
  50. PATT:linux$  
  51. HOLD:$  
  52. COMM:}  
  53. PATT:linux$  
  54. HOLD:$  
  55. PATT:ubuntu linux$  
  56. HOLD:$  
  57. COMM:/^linux/ {  
  58. PATT:ubuntu linux$  
  59. HOLD:$  
  60. PATT:fedora$  
  61. HOLD:$  
  62. COMM:/^linux/ {  
  63. PATT:fedora$  
  64. HOLD:$  
  65. [root@localhost ~]# sedsed -d   '/^linux/{=;p}' 1.txt  
  66. PATT:linux$  
  67. HOLD:$  
  68. COMM:/^linux/ {  
  69. COMM:=  
  70. 1 
  71. PATT:linux$  
  72. HOLD:$  
  73. COMM:p  
  74. linux  
  75. PATT:linux$  
  76. HOLD:$  
  77. COMM:}  
  78. PATT:linux$  
  79. HOLD:$  
  80. linux  
  81. PATT:centos$  
  82. HOLD:$  
  83. COMM:/^linux/ {  
  84. PATT:centos$  
  85. HOLD:$  
  86. centos  
  87. PATT:redhat$  
  88. HOLD:$  
  89. COMM:/^linux/ {  
  90. PATT:redhat$  
  91. HOLD:$  
  92. redhat  
  93. PATT:linux$  
  94. HOLD:$  
  95. COMM:/^linux/ {  
  96. COMM:=  
  97. 4 
  98. PATT:linux$  
  99. HOLD:$  
  100. COMM:p  
  101. linux  
  102. PATT:linux$  
  103. HOLD:$  
  104. COMM:}  
  105. PATT:linux$  
  106. HOLD:$  
  107. linux  
  108. PATT:ubuntu linux$  
  109. HOLD:$  
  110. COMM:/^linux/ {  
  111. PATT:ubuntu linux$  
  112. HOLD:$  
  113. ubuntu linux  
  114. PATT:fedora$  
  115. HOLD:$  
  116. COMM:/^linux/ {  
  117. PATT:fedora$  
  118. HOLD:$  
  119. fedora 

上面sedsed的调试显示了sed  -n的参数的实际实现:禁止自动打印模式空间内容.

sed 多行处理

  1. sed多行处理是通过n和N来实现  
  2. 多行Next(N)命令是相对next(n)命令的,后者将模式空间中的内容输出,然后把下一行读入模式空间,但是脚本并不会转移到开始而是从当前的n命令之后开始执行; 而前者则保存原来模式空间中的内容,再把新的一行读入,两者之间依靠一个换行符"\n"来分隔。在N命令执行后,控制流将继续用N命令以后的命令对模式空间进行处理.  
  3. 值得注意的是,在多行模式中,特殊字符"^"和"$"匹配的是模式空间的最开始与最末尾,而不是内嵌"\n"的开始与末尾. 

如下现在要将"Owner and Operator Guide"替换为"Installation Guide":

  1. [root@localhost ~]# cat 3.txt   
  2. Consult Section 3.1 in the Owner and Operator  
  3. Guide for a description of the tape drives  
  4. available on your system.  
  5. [root@localhost ~]# sedsed -d --hide=hold '/Operator$/{n;s/Owner and Operator\nGuide /Installation Guide\n/}' 3.txt  
  6. PATT:Consult Section 3.1 in the Owner and Operator$  
  7. COMM:/Operator$/ {  
  8. COMM:n  
  9. Consult Section 3.1 in the Owner and Operator  
  10. PATT:Guide for a description of the tape drives$  
  11. COMM:s/Owner and Operator\nGuide /nstallation Guide\n/  
  12. PATT:Guide for a description of the tape drives$  
  13. COMM:}  
  14. PATT:Guide for a description of the tape drives$  
  15. Guide for a description of the tape drives  
  16. PATT:available on your system.$  
  17. COMM:/Operator$/ {  
  18. PATT:available on your system.$  
  19. available on your system.  
  20. [root@localhost ~]# sedsed -d --hide=hold '/Operator$/{N;s/Owner and Operator\nGuide /Installation Guide\n/}' 3.txt  
  21. PATT:Consult Section 3.1 in the Owner and Operator$  
  22. COMM:/Operator$/ {  
  23. COMM:N  
  24. PATT:Consult Section 3.1 in the Owner and Operator\nGuide for a descr\  
  25. iption of the tape drives$  
  26. COMM:s/Owner and Operator\nGuide /nstallation Guide\n/  
  27. PATT:Consult Section 3.1 in the nstallation Guide\nfor a description \  
  28. of the tape drives$  
  29. COMM:}  
  30. PATT:Consult Section 3.1 in the nstallation Guide\nfor a description \  
  31. of the tape drives$  
  32. Consult Section 3.1 in the nstallation Guide  
  33. for a description of the tape drives  
  34. PATT:available on your system.$  
  35. COMM:/Operator$/ {  
  36. PATT:available on your system.$  
  37. available on your system. 

sed用于把文本读入模式空间或者模式空间的内容写入到指定文本中.
sed把模式空间的内容写入到指定文本中:由w和W实现
w filename:Write the current pattern space to filename.
W filename:Write the first line of the current pattern space to filename.
如下:

  1. [root@localhost ~]# cat 1.txt   
  2. linux server  
  3. centos  
  4. redhat  
  5. linux web  
  6. ubuntu linux  
  7. fedora  
  8. [root@localhost ~]# sed  -n '/^linux/,/^linux/w a.txt' 1.txt   
  9. [root@localhost ~]# cat a.txt  
  10. linux server  
  11. centos  
  12. redhat  
  13. linux web 

sed把文本读入模式空间由r实现

  1. [root@localhost ~]# cat 1.txt   
  2. linux server  
  3. centos  
  4. redhat  
  5. linux web  
  6. ubuntu linux  
  7. fedora  
  8. [root@localhost ~]# sed  '/centos/r /root/1.txt' 1.txt   
  9. linux server  
  10. centos  
  11. linux server  
  12. centos  
  13. redhat  
  14. linux web  
  15. ubuntu linux  
  16. fedora  
  17. redhat  
  18. linux web  
  19. ubuntu linux  
  20. fedora 

sed高级流控制

  1. b 分支:无条件转移 ,分支到脚本中带有标记的地方,如果分支不存在则分支到脚本的末尾.  
  2. t 有条件的转移,if分支,从最后一行开始,条件一旦满足或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾.  
  3. T 有条件的转移,错误分支,从最后一行开始,一旦发生错误或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾. 

[root@localhost ~]# cat 4.txt
a b c a d a a a
s d d d x s a
h j s a s h j h
j d f j a s j k j
要求:删除行内与第一列字符重复的字符,shell、sed、awk各写一个。达到这个结果:
a b c d
s d d d x a
h j s a s j
j d f a s k
这个例子来自http://blog.chinaunix.net/uid-10540984-id-3086644.html

  1. [root@localhost ~]# sed ':a;s/^\(.\)\(.*\) \1/\1\2/;ta' 4.txt   
  2. a b c d  
  3. s d d d x a  
  4. h j s a s j  
  5. j d f a s k  
  6. [root@localhost ~]# sedsed -d --hide=hold ':a;s/^\(.\)\(.*\) \1/\1\2/;ta' 4.txt   
  7. PATT:a b c a d a a a$  
  8. COMM::a  
  9. COMM:s/^\(.\)\(.*\) \1/\1\2/  
  10. PATT:a b c a d a a$  
  11. COMM:t a  
  12. COMM:s/^\(.\)\(.*\) \1/\1\2/  
  13. PATT:a b c a d a$  
  14. COMM:t a  
  15. COMM:s/^\(.\)\(.*\) \1/\1\2/  
  16. PATT:a b c a d$  
  17. COMM:t a  
  18. COMM:s/^\(.\)\(.*\) \1/\1\2/  
  19. PATT:a b c d$  
  20. COMM:t a  
  21. COMM:s/^\(.\)\(.*\) \1/\1\2/  
  22. PATT:a b c d$  
  23. COMM:t a  
  24. PATT:a b c d$  
  25. a b c d  
  26. PATT:s d d d x s a$  
  27. COMM::a  
  28. COMM:s/^\(.\)\(.*\) \1/\1\2/  
  29. PATT:s d d d x a$  
  30. COMM:t a  
  31. COMM:s/^\(.\)\(.*\) \1/\1\2/  
  32. PATT:s d d d x a$  
  33. COMM:t a  
  34. PATT:s d d d x a$  
  35. s d d d x a  
  36. PATT:h j s a s h j h$  
  37. COMM::a  
  38. COMM:s/^\(.\)\(.*\) \1/\1\2/  
  39. PATT:h j s a s h j$  
  40. COMM:t a  
  41. COMM:s/^\(.\)\(.*\) \1/\1\2/  
  42. PATT:h j s a s j$  
  43. COMM:t a  
  44. COMM:s/^\(.\)\(.*\) \1/\1\2/  
  45. PATT:h j s a s j$  
  46. COMM:t a  
  47. PATT:h j s a s j$  
  48. h j s a s j  
  49. PATT:j d f j a s j k j$  
  50. COMM::a  
  51. COMM:s/^\(.\)\(.*\) \1/\1\2/  
  52. PATT:j d f j a s j k$  
  53. COMM:t a  
  54. COMM:s/^\(.\)\(.*\) \1/\1\2/  
  55. PATT:j d f j a s k$  
  56. COMM:t a  
  57. COMM:s/^\(.\)\(.*\) \1/\1\2/  
  58. PATT:j d f a s k$  
  59. COMM:t a  
  60. COMM:s/^\(.\)\(.*\) \1/\1\2/  
  61. PATT:j d f a s k$  
  62. COMM:t a  
  63. PATT:j d f a s k$  
  64. j d f a s k  
  65.  
  66. 附加两种其他的解法  
  67. while read a b;do echo "$a ${b// $a}";done <4.txt 
  68. awk '{a=$1;gsub(" ?"a,"");print a""$0}' 4.txt