Sed:模式后的复杂替换(在同一行上)

时间:2013-08-20 02:12:14

标签: sed awk

假设你有这样的文字:

  foobar 42                  | ff 00 00 00 00
  foobaz 00                  | 0a 00 0b 00 00
  foobie 00                  | 00 00 00 00 00
  bar    00                  | ab ba 00 cd 00

并且您希望将00右侧的所有非|更改为(),但仅限|的LHS } 00。期望的结果:

  foobar 42                  | ff 00 00 00 00
  foobaz 00                  | (0a) 00 (0b) 00 00
  foobie 00                  | 00 00 00 00 00
  bar    00                  | (ab) (ba) 00 (cd) 00

有没有一种很好的方法可以使用sed进行此操作,或者我是否试图超越语言的功能?

到目前为止,这是我的工作:

s/[^0]\{2\}/(&)/g包装您的RHS值

/[^|]*00[^|]*|/可用作命令的地址,仅在有效行上运行

现在的诀窍是制定一个在模式空间的一部分中执行的命令。

这实际上不是面向行的,这可以解释为什么我无法获得一个有效的表达式。

5 个答案:

答案 0 :(得分:4)

$ awk 'BEGIN{ FS=OFS="|" } $1~/ 00 /{gsub(/[^ ][^0 ]|[^0 ][^ ]/,"(&)",$2)} 1' file
  foobar 42                  | ff 00 00 00 00
  foobaz 00                  | (0a) 00 (0b) 00 00
  foobie 00                  | 00 00 00 00 00
  bar    00                  | (ab) (ba) 00 (cd) 00

如果您要搜索的字符串变得比2 0更复杂,这里是一种更通用的可扩展方法,因为它不需要您编写否定该字符串的RE:

$ awk '
    BEGIN{ FS=OFS="|" }
    $1 ~ / 00 /{
        split($2,a,/ /)
        $2=""
        for (i=2;i in a;i++)
            $2 = $2 " " (a[i] == "00" ? a[i] : "(" a[i] ")")
    }
    1
' file
  foobar 42                  | ff 00 00 00 00
  foobaz 00                  | (0a) 00 (0b) 00 00
  foobie 00                  | 00 00 00 00 00
  bar    00                  | (ab) (ba) 00 (cd) 00

答案 1 :(得分:3)

这可能适合你(GNU sed):

 sed -r '/^\s*\S+\s*00/!b;s/\b([^0][^0]|0[^0]|[^0]0)\b/(&)/g' file

这忽略了不以单词后跟00开头的行。然后插入2个字符串的parens,这些字符串既不是0,也不包含0和非0。

答案 2 :(得分:2)

很好看,(虽然我一直都这么做),管道上的sed sed sed意味着我第一次做不对:这里有一个

sed -r '/00.*\|/  {   ## match lines with a zero before the pipe

    ### surround tailing digits with ()
    ##  
     s/(\w\w) (\w\w) (\w\w) (\w\w) (\w\w)$/(\1) (\2) (\3) (\4) (\5)/;  

    ### replace the zeroes (00) with 00
    ##
    s/\(00\)/00/g; 

}'  txt
  foobar 42                  | ff 00 00 00 00
  foobaz 00                  | (0a) 00 (0b) 00 00
  foobie 00                  | 00 00 00 00 00
  bar    00                  | (ab) (ba) 00 (cd) 00

OK!

答案 3 :(得分:1)

好的尝试一下!

$ sed '/00 *|/ { h; s/|.*/|/; x; s/.*|//; s/\(0[1-9a-f]\|[1-9a-f][0-9a-f]\)/(\1)/g; H; x; s/\n//; }' yourfile.txt

我得到的输出是:

foobar 42                  | ff 00 00 00 00
foobaz 00                  | (0a) 00 (0b) 00 00
foobie 00                  | 00 00 00 00 00
bar    00                  | (ab) (ba) 00 (cd) 00

已编辑,因此在00之前不会触及|之前的行。

答案 4 :(得分:1)

我认为awk可能是这项工作的更好工具,但可以使用sed完成:

sed '/^[^ ]*  *00 *|/{
         :a
         s/\(|.*[^(]\)\([0-9a-f][1-9a-f]\)/\1(\2)/
         t a
         :b
         s/\(|.*[^(]\)\([1-9a-f][0-9a-f]\)/\1(\2)/
         t b
     }' data

该脚本在管道之前查找包含00的行,并仅将操作应用于这些行。有两个替换操作,每个操作都包含在一个循环中。 :a:b行是标签。如果自上次跳转后执行了替换,则t at b命令是对指定标签的条件跳转。这两个替换几乎是对称的;第一个处理任何不以0结尾的数字;第二个处理任何不以0开头的数字;在他们之间,他们忽略了00。模式查找管道,任何不以空心括号(结尾的字符序列,以及相应的数字对;它取代了它,以便数字在括号内结束。循环是必要的,因为g修饰符不会从头开始,并且模式在数字中向后工作。

鉴于此数据文件(您的稍微扩展版本):

foobar 42                  | ff 00 00 00 00
foobaz 00                  | 0a 00 0b 00 00
foobie 00                  | 00 00 00 00 00
bar    00                  | ab ba 00 cd 00
fizbie    00               | ab ba 00 cd 90
fizzbuzz    00             | ab ba 00 cd 09

脚本的输出是:

foobar 42                  | ff 00 00 00 00
foobaz 00                  | (0a) 00 (0b) 00 00
foobie 00                  | 00 00 00 00 00
bar    00                  | (ab) (ba) 00 (cd) 00
fizbie    00               | (ab) (ba) 00 (cd) (90)
fizzbuzz    00             | (ab) (ba) 00 (cd) (09)

在每个替换命令之后添加p具有中等教育意义,因此您可以看到替换如何工作:

foobar 42                  | ff 00 00 00 00
foobaz 00                  | 0a 00 (0b) 00 00
foobaz 00                  | (0a) 00 (0b) 00 00
foobaz 00                  | (0a) 00 (0b) 00 00
foobie 00                  | 00 00 00 00 00
bar    00                  | ab ba 00 (cd) 00
bar    00                  | ab (ba) 00 (cd) 00
bar    00                  | (ab) (ba) 00 (cd) 00
bar    00                  | (ab) (ba) 00 (cd) 00
fizbie    00               | ab ba 00 (cd) 90
fizbie    00               | ab (ba) 00 (cd) 90
fizbie    00               | (ab) (ba) 00 (cd) 90
fizbie    00               | (ab) (ba) 00 (cd) (90)
fizbie    00               | (ab) (ba) 00 (cd) (90)
fizzbuzz    00             | ab ba 00 cd (09)
fizzbuzz    00             | ab ba 00 (cd) (09)
fizzbuzz    00             | ab (ba) 00 (cd) (09)
fizzbuzz    00             | (ab) (ba) 00 (cd) (09)
fizzbuzz    00             | (ab) (ba) 00 (cd) (09)