【问题标题】:BASH append line to earlier line if preceded by spaces如果前面有空格,则 BASH 将行附加到前面的行
【发布时间】:2017-04-08 01:05:32
【问题描述】:

我有一个看起来像这样的文件:

t2_this_is_some_output_80_pool
            address 12.34.56.78
            state down
            address 13.34.56.78
            state down
t2_this_is_a_different_output_80_pool
            address 14.34.56.78
t2_this_is_another_output_80_pool
            address 15.34.56.78
            state up    

我想输出它,所以它看起来像:

t2_this_is_some_output_80_pool address 12.34.56.78 state down
t2_this_is_some_output_80_pool address 13.34.56.78 state down
t2_this_is_a_different_output_80_pool address 14.34.56.78
t2_this_is_another_output_80_pool 15.34.56.78 state up

我一直在尝试使用 BASH、awk 和 sed,但我所做的一切都无法为我提供所需的输出。

我尝试过的事情之一:

用 = 替换开头的 12 个空格,如果行以 = 开头,则追加到上一行

cat file.txt | sed 's/            /=/' | sed -e :a -e '$!N;s/\n=/ /;ta' -e 'P;D'

但这不起作用...

任何帮助都会得到很大的帮助:-)

【问题讨论】:

  • 我很确定 sed 可以解决问题。
  • 请显示 bash、awk 或 sed 尝试,以便我们在您遇到问题的地方提供帮助。
  • 已更新。我粘贴在帖子的第一个 daft 中,而不是第二个 face palm

标签: bash awk sed


【解决方案1】:

大概是这样的:

$ cat f1
t2_this_is_some_output_80_pool
            address 12.34.56.78
            state down
            address 13.34.56.78
            state down
t2_this_is_a_different_output_80_pool
            address 14.34.56.78
t2_this_is_another_output_80_pool
            address 15.34.56.78
            state up    

$ echo $(cat f1) | sed 's/t2/\nt2/g'

t2_this_is_some_output_80_pool address 12.34.56.78 state down address 13.34.56.78 state down 
t2_this_is_a_different_output_80_pool address 14.34.56.78 
t2_this_is_another_output_80_pool address 15.34.56.78 state up

【讨论】:

    【解决方案2】:
    sed ':a; $!N;s/\n[ ]\+/ /;ta;P;D' yourfile.txt
    

    $!N 如果不是最后一行,则追加下一行。

    s\n[ ]\+/ / 用一个空格替换新行之后的所有空格。

    ta如果有匹配,转到标签:a

    Pprint 修改的行

    D删除旧版行

    【讨论】:

      【解决方案3】:

      下面是一个简单的选项,将 sed 反向引用和您的 = 标识符结合起来:

      sed -r 's/^([^ ])/=\1/g' file.txt |tr '\n' ' ' |tr '=' '\n' |sed -r 's/ +/ /g'
      

      如果我正确地回答了您的问题,这将给出以下输出,这可能不是您正在寻找的内容(因为它不会在每个地址的开头使用相应的t2_ 开始一个新行):

      t2_this_is_some_output_80_pool address 12.34.56.78 state down address 13.34.56.78 state down 
      t2_this_is_a_different_output_80_pool address 14.34.56.78 
      t2_this_is_another_output_80_pool address 15.34.56.78 state up
      

      说明:

      1. sed -r 's/^([^ ])/=\1/g':在每行的开头放置一个 = 字符,而不是以空格开头。

      输出:

      =t2_this_is_some_output_80_pool
                  address 12.34.56.78
                  state down
                  address 13.34.56.78
                  state down
      =t2_this_is_a_different_output_80_pool
                  address 14.34.56.78
      =t2_this_is_another_output_80_pool
                  address 15.34.56.78
                  state up
      
      1. tr '\n' ' ':将每个换行符替换为空格字符。

      输出:

      =t2_this_is_some_output_80_pool             address 12.34.56.78             state down             address 13.34.56.78             state down =t2_this_is_a_different_output_80_pool             address 14.34.56.78 =t2_this_is_another_output_80_pool             address 15.34.56.78             state up 
      
      1. tr '=' '\n':将每个 = 字符替换为换行符。

      输出:

      t2_this_is_some_output_80_pool             address 12.34.56.78             state down             address 13.34.56.78             state down 
      t2_this_is_a_different_output_80_pool             address 14.34.56.78 
      t2_this_is_another_output_80_pool             address 15.34.56.78             state up 
      
      1. sed -r 's/ +/ /g':将所有连续的空格字符替换为单个空格字符。

      输出:

      t2_this_is_some_output_80_pool address 12.34.56.78 state down address 13.34.56.78 state down 
      t2_this_is_a_different_output_80_pool address 14.34.56.78 
      t2_this_is_another_output_80_pool address 15.34.56.78 state up 
      

      【讨论】:

        【解决方案4】:
        awk '
        /^[^[:blank:]+]/{                     # search for record/line does not start with blank
                    if(s){print s; s=""}      # This is whenever state not found then print variable s
                    p=$0                      # store record in varibale p   
                    next                      # stop processing go to next line
        }
        {                             
              gsub(/^[ \t]+/,"")              # suppress starting space/tab char 
              s = s ? s OFS $0: p OFS $0      # if variable s has something then concatenate variable s with current record else variable p and current record
        }
        /state/{                              # if record has word state then 
              print s; s=""                   # print variable s and reset variable
        }
        END{                                  # end block
             if(s)print s                     # if s has something print s
        }' file 
        

        Oneliner

        $ awk '/^[^[:blank:]+]/{if(s){print s; s=""}p=$0; next}{gsub(/^[ \t]+/,"");s = s ? s OFS $0: p OFS $0; }/state/{print s; s=""}END{if(s)print s}' file
        

        输入

        $ cat f
        t2_this_is_some_output_80_pool
                    address 12.34.56.78
                    state down
                    address 13.34.56.78
                    state down
        t2_this_is_a_different_output_80_pool
                    address 14.34.56.78
        t2_this_is_another_output_80_pool
                    address 15.34.56.78
                    state up 
        

        输出

        $ awk '
        /^[^[:blank:]+]/{
                    if(s){print s; s=""}
                    p=$0; 
                    next
        }
        {
              gsub(/^[ \t]+/,"")
              s = s ? s OFS $0: p OFS $0 
        }
        /state/{
              print s; s=""
        }
        END{
             if(s)print s
        }' f
        t2_this_is_some_output_80_pool address 12.34.56.78 state down
        t2_this_is_some_output_80_pool address 13.34.56.78 state down
        t2_this_is_a_different_output_80_pool address 14.34.56.78
        t2_this_is_another_output_80_pool address 15.34.56.78 state up  
        

        【讨论】:

        • Akshay,太棒了!我认为我可以看到它是如何工作的 :-) 非常感谢您的帮助!非常感谢所有给我答案的人!猜猜我需要再次挖掘我的书!
        【解决方案5】:
        sed '
        # for every new section (starting with non space)
           /^[^[:blank:]]/ {
        # copy it to the hold buffer
              h
        # delete the line (and go to next line)
              d
              }
        # other line(s)
        # add next line
           N
        # add holding buffer to current line (with new line between)
           G
        # reformat, removing new line followed by spaces and putitnging last line in front
           s/[[:blank:]]*\([^[:blank:]].*\)\^J[[:blank:]]*\([^[:blank:]].*\)\^J\(.*\)/\3 \1 \2/
        # print the resulting line
           ' YourFile
        

        在线POSIX中如此

        sed -e '/^[^[:blank:]]/{h;d' -e '};N;G;s/[[:blank:]]*\([^[:blank:]].*\)\^J[[:blank:]]*\([^[:blank:]].*\)\^J\(.*\)/\3 \1 \2/' YourFile
        

        注意:\^J 是真正的换行符 CTRL+V+J。 \n avalaible for gawk 和 \ with new line for POSIX 是等效的

        【讨论】:

          【解决方案6】:

          我相信使用简单的 awk 脚本会更容易理解,例如:

          awk '
          BEGIN {
              separator_address = "address" # Put what you want here
              line=""
              addr=""
              args=""
          }
          {
              if (substr($0, 1, 1) != " ") { # Start by a space
                  if (addr != "") {
                      print line" "addr" "args
                  }
                  line=$0
                  addr = ""
                  args = ""
                  next # Nothing more to do here
              }
              gsub(/^[ \t]+/,"",$0) # Remove spaces
              if (substr($0, 1, length(separator_address)) == separator_address) { 
                  if (addr == "") { 
                      addr = $0
                  } else { 
                      print line" "addr" "args
                      addr = $0
                      args = ""
                  } 
              } else { 
                  args = $0
              } 
          }
          END {
              if (addr != "") {
                  print line" "addr" "args
              }
          }' file.txt
          

          Sed 确实非常强大,但在多行处理方面并不是很方便。 但是因为我真的不希望如何分割行,所以我使用了分隔符(“地址”)。如果它是两行,则可以使用标志而不是分隔符(例如,初始化为 0,如果读取以空格开头的某个值,则 +1,如果达到 2,则打印,例如,在每次打印后重新初始化)。

          结果:

          t2_this_is_some_output_80_pool address 12.34.56.78 state down
          t2_this_is_some_output_80_pool address 13.34.56.78 state down
          t2_this_is_a_different_output_80_pool address 14.34.56.78
          t2_this_is_another_output_80_pool 15.34.56.78 state up
          

          【讨论】:

            【解决方案7】:

            @try:还有一种方法。

            awk '{ORS=$0 ~ /^ +/?"":RS} {$1=$1} 1; END{print RS}'  Input_file
            

            编辑:现在在这里添加代码解释也很成功。

            awk '{
            ORS=           ##### Setting ORS(Output record separator) here, where output field separator is awk's default keyword whose default value is a new line.
            $0 ~ /^ +/     ##### Checking if any record/line is starting from space here.
            ?              ##### Conditional operator here, which will execute it's following statements if above mentioned condition is TRUE.
            ""             ##### If above mentioned conditions is TRUE then setting ORS's value to NULL.
            :              ##### : is a conditional operator here, which will execute the statements following it when conditions is FALSE.
            RS}            ##### Setting ORS's value to RS(Record separator) whose default value will be a new line.
            {$1=$1}        ##### Resetting the $1(first field) here, so that value of ORS could be reflected here.
            1;             ##### Mentioning 1 here. awk works on condition then action method, so I am making condition TRUE here and not mentioning any action here so by default print action will happen here.
            END{print RS}  ##### in this block printing the RS(record separator)'s value here.
            '  Input_file  ##### mentioning the Input_file here.
            

            【讨论】:

              【解决方案8】:

              如果您不介意开头有一个额外的换行符,而结尾处没有,那么这个简短的脚本可以:

              awk '/^[^ ]/ { printf "\n" } $1=$1' ORS=' '
              

              您可以通过分别添加NR>1END { print "\n" } 来解决这两个问题。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2011-09-21
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-10-18
                • 1970-01-01
                相关资源
                最近更新 更多