【问题标题】:How to merge multiple lines into single line but only for block of lines separated by blank line如何将多行合并为单行,但仅适用于由空行分隔的行块
【发布时间】:2019-08-22 02:29:01
【问题描述】:

我正在尝试将多行合并为单行,但有附加条件。

我的输入文件如下所示:

Dm1*(  stuff1 + stuff2 -
stuff3 + stuff4)

+ D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 +
  D1stuff5 - 
  D1stuff6 )

+ D2*(D2stuff)

所以有多行也用空行分隔。所有的*stuff* 都包含长而复杂的表达式,也可以包含括号。

我想保留空白行,但合并其他多行。

预期的输出是

Dm1*(  stuff1 + stuff2 - stuff3 + stuff4)

+ D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 + D1stuff5 - D1stuff6 )

+ D2*(D2stuff)

当前的所有尝试都喜欢

awk '{printf("%s",$0)}' 

将所有内容放在一行中。我应该遍历行还是有什么方法可以识别空行之间的块并将其应用到其中?

【问题讨论】:

    标签: bash awk sed sh


    【解决方案1】:

    甚至比 John1024 的版本短了一点

    awk 'BEGIN { RS=""; ORS="\n\n"}{$1=$1}1'
    

    awk -v RS="" -v ORS="\n\n" '{$1=$1}1'
    

    使用RS="" 告诉 awk 使用任何段落作为记录(即由空行分隔的文本块)。但它也告诉 awk 始终是与FS 组合的字段分隔符。只需重新定义输出记录分隔符ORS,我们就可以通过重置第一条记录$1=$1 告诉awk 重新定义其记录$0 来输出您想要的所有内容。这意味着由FS(这里的默认值)和换行符(由于RS="")定义的所有字段分隔符都被OFS(默认为)替换。最后我们用1打印记录

    另外设置OFS=""可以去掉所有空格

    RS RS的字符串值的第一个字符为输入记录分隔符; 默认情况下。如果RS 包含多个字符,则未指定结果。如果RSnull,则记录由 加上一个或多个空行组成的序列分隔,前导或尾随空行不应导致输入的开头或结尾处为空记录,并且 应始终是字段分隔符,无论 FS 的值是什么。

    来源:POSIX awk standard

    【讨论】:

    • { 之前的第二个中缺少'
    • 是的,这是使用 awk 执行此操作的正确/惯用方式。
    【解决方案2】:
    awk '{if(NF!=0){printf $0}else{printf "\n\n"}}'
    

    【讨论】:

      【解决方案3】:

      试试:

      $ awk -v RS=  '{gsub(/ *\n */, " "); print $0 ORS}' file
      Dm1*(  stuff1 + stuff2 - stuff3 + stuff4)
      
      + D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 + D1stuff5 - D1stuff6 )
      
      + D2*(D2stuff)
      

      它是如何工作的:

      • -v RS=

        这告诉 awk 使用空行作为记录分隔符。

      • gsub(/ *\n */, " ")

        这告诉 awk 用一个空格替换记录中的任何换行符以及周围的任何空格。

      • print $0 ORS

        这告诉 awk 打印记录,后跟输出记录分隔符 ORS,默认情况下是换行符。

      【讨论】:

        【解决方案4】:

        除了John1024 引入的非常好的awk 命令之外,您还可以使用sed 方法来解决您的问题。

        输入:

        $ cat input_file 
        Dm1*(  stuff1 + stuff2 -
        stuff3 + stuff4)
        
        + D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 +
          D1stuff5 -
          D1stuff6 )
        
        + D2*(D2stuff)
        

        命令:

        sed -n '/^$/!{H};/^$/{x;s/\n//g;s/$/\n/;p;};${x;s/\n//g;p}' input_file
        

        输出:

        Dm1*(  stuff1 + stuff2 -stuff3 + stuff4)
        
        + D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 +  D1stuff5 -  D1stuff6 )
        
        + D2*(D2stuff)
        

        说明:

        • -n 停用 sed 自动打印
        • /^$/!{H};sed 遇到非空行时/^$/! 通过H 将此行附加到保留空间中
        • /^$/{x;s/\n//g;s/$/\n/;p;}sed遇到空行/^$/,交换保持空间和模式空间x,去掉已经构造好的s/\n//g字符串中的所有\n,在后面加一个\n字符串结尾s/$/\n/,打印它p
        • ${x;s/\n//g;p}sed 到达最后一行时,交换保持/模式空格x,然后在打印之前通过s/\n//g 删除所有\n p

        【讨论】:

          【解决方案5】:

          使用 Perl 段落模式

          perl -00 -ne ' s/\n//g; print "$_\n\n" ' file
          

          您的意见

          $ cat bogey.txt
          Dm1*(  stuff1 + stuff2 -
          stuff3 + stuff4)
          
          + D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 +
            D1stuff5 -
            D1stuff6 )
          
          + D2*(D2stuff)
          $ perl -00 -ne ' s/\n//g; print "$_\n\n" ' bogey.txt
          Dm1*(  stuff1 + stuff2 -stuff3 + stuff4)
          
          + D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 +  D1stuff5 -   D1stuff6 )
          
          + D2*(D2stuff)
          
          $
          

          【讨论】:

            【解决方案6】:

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

            sed ':a;N;/\n$/!s/\n//;ta' file
            

            在模式空间中收集行,删除换行符,直到空行。

            【讨论】:

            • 这适用于 GNU sed。但是我更喜欢在 GNU 和 BSD 平台上都可以使用的东西,因为我经常同时使用这两种平台。
            • @Boogeyman 也许sed $':a;N;/\\n$/!s/\\n//;ta' file 会起作用,或者也许sed -e ':a' -e $'N;/\\n$/!\\n//;ta' file
            猜你喜欢
            • 2012-12-10
            • 2021-07-04
            • 1970-01-01
            • 2017-02-05
            • 1970-01-01
            • 1970-01-01
            • 2018-03-19
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多