首页 文章

如何在SED中的行范围内用冒号替换换行符

提问于
浏览
1

我想搜索文件中的行范围,这些行以start开头并以End结尾,并用冒号替换换行符 . 我需要在SED或AWK中完成此操作 .

示例文件:

start
a
b
c
End
Start
a
b
c
End
Start
x
y
z
End

预期产出:

a:b:c
a:b:c
x:y:z

6 回答

  • 1

    这个短awk单行应该工作:

    awk -v RS='Start|End' -v OFS=":" '$1=$1' file
    

    与您的数据:

    kent$  cat f
    Start
    a
    b
    c
    End
    Start
    a
    b
    c
    End
    Start
    x
    y
    z
    End
    
    kent$  awk -v RS='Start|End' -v OFS=":" '$1=$1' f
    a:b:c
    a:b:c
    x:y:z
    
  • 4

    这是一个版本:

    awk '/End/{print a;f=a=0} f {a=a?a":"$0:$0} /(S|s)tart/{f=1}' file
    a:b:c
    a:b:c
    x:y:z
    

    我猜第一个 start 中有一个拼写错误,如果是这样的话:

    awk '/End/{print a;f=a=0} f {a=a?a":"$0:$0} /Start/{f=1}' file
    

    /End/{print a;f=a=0} 如果行包含 End print a ,并将 fa 设置为 0
    f {a=a?a":"$0:$0} 如果 f 为真,则首次运行时将 a 设置为 $0 ,下次运行时设置为 :$0
    /Start/{f=1} 如果行有 Start 设置 f1 (真)

  • 0

    让我们试试 awk .

    $ awk '/start/ || /Start/ {next} /End/ {print line; line=""; next} {if (line) {line=line":"} line=line$0}' file
    a:b:c
    a:b:c
    x:y:z
    

    解释

    • /start/ || /Start/ {next} 在包含"start"或"Start"的行上,跳过 .

    • /End/ {print line; line=""; next} 在包含 End 的行上,打印包含已加载信息的 line 变量 . 删除var的值并转到下一行 .

    • {if (line) {line=line":"} line=line$0} 在其余行上,继续在 line 变量中加载数据 . if 条件是为了避免尾随 : .

    /start/ || /Start/ {next} 可以缩减为这两个(thanks Jotne):

    /start|Start/ {next}
    
    /(s|S)tart/ {next}
    
  • 1

    如果开始和结束之间总共有3行:

    grep -iv 'start\|end' file | paste -d: - - -
    
  • 0
    sed -n '/Start/,/End/ {
       /Start/ !{
          /End/ !H
          }
       /End/ {
          s/.*//
          x
          s/\n/:/g
          s/://
          p
          }
       }
    /Start/,/End/ !p' YourFile
    

    如果 startStart 应该在代码中用 [sS]tart 替换 Start (和 /start/ || /Start/ {next}[eE]nd

    Explaination

    除非特定要求,否则在不打印输出的情况下启动sed

    /Start/,/End/ {
    

    对于以 Start 开头并以 End 结尾的任何行块(在单独的行上)

    /Start/ !{
              /End/ !H
              }
    

    如果行不包含( !Start 而不是 End ,则将该行添加(追加)到保持缓冲区(存储类型)

    /End/ {
       s/.*//
       x
       s/\n/:/g
       s/://
       p
       }
    

    到达包含 End 的行时

    • 删除当前行( End

    • 交换( x )保持缓冲区(存储了所有行的行)和工作缓冲区(可以操作且通常具有当前行的缓冲区)

    • : 更改所有新行(缓冲区包含交换后新行分隔的所有行)

    • 首先删除 : (由于首先添加插入新行)

    • 打印内容

    /开始/,/结束/!p

    对于 StartEnd 之间的块之间的所有行( ! ),打印出来

  • 1

    只是GNU awk的另一种方法:

    $ gawk -v RS='\0' '{ gsub(/\n/,":"); gsub(/:End:Start:/,"\n"); gsub(/^start:|:End:$/,"") }1' file     
    a:b:c
    a:b:c
    x:y:z
    

    这里发布的其他awk解决方案也很好 .

相关问题