合并该模式后的每两行,直到下一个模式

合并该模式后的每两行,直到下一个模式

文件.txt

String1?
word1
word2
word3
word4

String2?
word5
word6
word7
word8

期望的输出:

String1?
word1 | word2
word3 | word4

String2?
word5 | word6
word7 | word8

唯一的模式是我尝试过的线条/?$/

sed '/\?$/{n;:l N;/\?$/b; :a; N; $!b a; s/\n\s\{1,\}/ | /g; bl}'

但这没有用。我当前的工作解决方案:

sed '/\?$/{:a;N;/\n....-..-.. /!s/\n/ - /;ta;P;D}' | sed 's/^[- ]*//g;s/[ -]*$//g'

...但这是一种解决方法,而且速度非常慢。任何人都可以帮助解决没有管道的单个内衬并且是一种快速的解决方案吗?

如果不存在空行,如在模式中,$\|^$,并且如果 ^$ 不存在并且有另一行带有 ?$,那么我们如何将缓冲区从 ?$ 保存到第一个非贪婪 ?$ 模式,然后打印除最后一行之外的所有行并将最后一行与下一个模式缓冲区合并以进行搜索?

答案1

仅限 GNU sed。
如果该块的所有行都恰好有 2 列(您的情况):

sed '/?$\|^$/b;N;s/\n/ | /' File.txt

如果奇数内容是可能的(通用方式):

sed '/?$\|^$/b;N;/\n$/!s/\n/ | /' File.txt

答案2

假设您的输入是由空行分隔的文本块,如示例输入所示,然后在每个 Unix 机器上的任何 shell 中使用任何 awk:

$ awk -v RS= -F'\n' -v OFS=' | ' '{print $1; for (i=2; i<NF; i+=2) print $i, $(i+1); print ""}' file
String1?
word1 | word2
word3 | word4

String2?
word5 | word6
word7 | word8

答案3

$ sed '/?$/,/^$/ { //b; N; y/\n/|/; }' file
String1?
word1|word2
word3|word4

String2?
word5|word6
word7|word8

对于 范围内的行/?$/,/^$/,即从?末尾带有 a 的行到空行:

  • 如果当前行是范围中的第一行或最后一行,则不执行任何操作(//b;“如果最近匹配的正则表达式(在此循环中)匹配,则分支到脚本末尾”)。
  • 否则,将下一行输入追加到缓冲区 ( N),并用一个字符替换插入的换行符|。如果您希望管道周围有间距,请使用s/\n/ | /代替y/\n/|/

POSIX-ly:

sed -e '/?$/,/^$/ { //b' -e N -e 'y/\n/|/' -e '}' file

或者,使用单独的脚本文件,通过此处文档提供,

sed -f /dev/stdin file <<'END_SED'
/?$/,/^$/ {
    // b
    N
    y/\n/|/
}
END_SED

同样的事情与awk,

awk -v OFS='|' '
    /\?$/,length == 0 {
        if ( !/\?$/ && length != 0) {
            getline n
            print $0, n
        } else print
    }' file

上面的代码也可以用来/^$/代替,如果您希望输出中的管道分隔符周围有空格,则length == 0可以使用 来OFS=' | '代替。OFS='|'

答案4

Perl 在段落模式 (-00) 中我们可以执行以下操作:-

perl -aF'\n' -nls -00e '
  print shift @F;
  print splice(@F,0,2) while @F>1;
  print @F if !eof;
' -- -,=" | " file

在其扩展正则表达式模式 (-E) 中使用 GNU sed 来简化正则表达式编写:

sed -E '
  /./{H;$!d;}
  x;$!G;s///
  s/([^\n]*\n){2}/&|/g
  s/\n\|/ | /g
' file

相关内容