文件.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