【问题标题】:SED remove new line lines containing a patternSED 删除包含模式的新行行
【发布时间】:2015-03-29 18:18:55
【问题描述】:

我想删除(sed 或 awk)所有仅包含一次字符 " 的行上的换行符,但是一旦在该行上删除了换行符,就可以在下一行删除它。

这是一个例子

line1"test 2015"
line2"test
2015"
line3"test 2020"
line4"test
2017"

应该转化为:

line1"test 2015"
line2"test2015"
line3"test 2020"
line4"test2017"

【问题讨论】:

    标签: awk sed


    【解决方案1】:

    使用 sed:

    sed '/[^"]$/{N;s/\n//}' file
    

    输出:

    第 1 行“测试 2015” 第 2 行“测试 2015” line3“测试2020” 第 4 行“测试 2017”

    搜索 (//) 不 (^) 以单个字符 " 结尾 ($) 的行。仅适用于这些行 ({}):将下一行 (N) 附加到 sed 的模式空间(当前行)并使用 sed 的搜索和替换 (s///) 在模式空间中查找现在嵌入的换行符 (\n ) 并替换为空。

    【讨论】:

      【解决方案2】:

      使用 GNU awk:

      awk -v RS='"' 'NR % 2 == 0 { gsub(/\n/, ""); } { printf("%s%s", $0, RT) }' filename
      

      这是最直接的方法。使用"作为记录分隔符,

      NR % 2 == 0 {             # in every other record (those inside quotes)
        gsub(/\n/, "")          # remove the newlines
      }
      { 
        printf("%s%s", $0, RT)  # then print the line terminated by the same thing
                                # as in the input (to avoid an extra quote at the
                                # end of the output)
      }
      

      RT 是一个 GNU 扩展,这就是为什么这需要 gawk。

      使用 sed

      用 sed 做这件事的难点在于引号之间可能有两个换行符,比如

      line2"test
      123
      2015"
      

      这使得在条件之后仅获取一行变得脆弱。因此:

      sed '/^[^"]*"[^"]*$/ { :a /\n.*"/! { N; ba; }; s/\n//g; }' filename
      

      即:

      /^[^"]*"[^"]*$/ {   # When a line contains only one quote
        :a                # jump label for looping
        /\n.*"/! {        # until there appears another quote
          N               # fetch more lines
          ba
        }
        s/\n//g           # once done, remove the newlines.
      }
      

      作为单行程序,这需要 GNU sed,因为 BSD sed 对分支指令的格式很挑剔。但是,应该可以将代码的扩展形式放入一个文件中,例如 foo.sed,然后使用 BSD sed 运行 sed -f foo.sed filename

      请注意,此代码假定在开始引号之后,包含引号的下一行仅包含该引号。如果需要,解决该问题的方法是

      sed ':a h; s/[^"]//g; s/""//g; /"/ { x; N; s/\n//; ba }; x' filename
      

      ...但这可以说超出了 sed 应该合理完成的事情的范围。它的工作原理是这样的:

      :a           # jump label for looping
      h            # make a copy of the line
      s/[^"]//g    # isolate quotes
      s/""//g      # remove pairs of quotes
      /"/ {        # if there is a quote left (number of quotes is odd)
        x          # swap the unedited text back into the pattern space
        N          # fetch a new line
        s/\n//     # remove the newline between them
        ba         # loop
      }
      x            # swap the text back in before printing.
      

      使用非 GNU awk

      每行有几个引号的情况在 aw​​k 中比在 sed 中更容易处理。上面的 GNU awk 代码是隐式执行的;对于非 GNU awk,它需要做更多的事情(但不是很严重):

      awk -F '"' '{ n = 0; line = ""; do { n += NF != 0 ? NF - 1 : 0; line = line $0 } while(n % 2 == 1 && getline == 1) print line }' filename
      

      主要技巧是使用" 作为字段分隔符,以便字段数告诉我们行中有多少引号。那么:

      {
                                             # reset state
        n = 0                                # n is the number of quotes we have
                                             # seen so far
        line = ""                            # line is where we assemble the output
                                             # line
      
        do {
          n += NF != 0 ? NF - 1 : 0;         # add the number of quotes in the line
                                             # (special handling for empty lines
                                             # where NF == 0)
          line = line $0                     # append the line to the output
        } while(n % 2 == 1 && getline == 1)  # while the number of quotes is odd
                                             # and there's more input, get new lines
                                             # and loop
      
        print line                           # once done, print the combined result.
      }
      

      【讨论】:

        【解决方案3】:

        这可能对你有用(GNU sed):

        sed -r ':a;N;s/^([^\n"]*"[^\n"]*)\n/\1 /;ta;P;D' file
        

        这会将两行之间的换行符替换为第一行仅包含一个双引号的空格。

        注意该空间也可能被删除,但数据表明它。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-08-31
          • 1970-01-01
          • 2013-08-22
          • 2014-09-30
          • 1970-01-01
          • 2016-10-07
          • 2013-12-01
          • 2015-04-08
          相关资源
          最近更新 更多