如果前面有空格,BASH会将行添加到前一行

时间:2017-04-07 11:27:02

标签: bash awk sed

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

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'

但那不起作用......

任何帮助都会受到极大的欢迎: - )

8 个答案:

答案 0 :(得分:1)

以下是一个简单的选项,它结合了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':在每行的开头放一个=字符,而不是以空格开头。
  2. 输出:

    =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' ' ':用空格字符替换每个换行符。
    2. 输出:

      =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':用换行符替换每个=个字符。
      2. 输出:

        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':用一个空格字符替换所有连续空格字符。
        2. 输出:

          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 :(得分: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 :(得分:1)

sed ':a; $!N;s/\n[ ]\+/ /;ta;P;D' yourfile.txt

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

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

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

P打印修改后的行

D删除旧版本的

答案 3 :(得分:0)

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可用于gawk和\使用POSIX的新行等效

答案 4 :(得分:0)

我相信使用简单的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确实非常强大,但在多线治疗方面并不是很方便。 但由于我并不是真的想要分割线,我使用了一个分隔符(&#34;地址&#34;)。如果是两行,则可以使用标志而不是分隔符(初始化为0,如果读取以空格开头的值,则为+1,如果达到2则打印,例如,在每次打印后重新初始化)。 / p>

结果:

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

答案 5 :(得分:0)

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  

答案 6 :(得分:0)

@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.

答案 7 :(得分:0)

如果你不介意在开头有一个额外的新行,而在最后没有,那么这个简短的脚本就可以了:

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

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