如何使用 awk 或 sed 在确切位置合并两行,就好像它被拉 up/down
How to merge two lines in the exact place as if it is pulled up/down using awk or sed
这里给出了我的文件的示例输出
! S R Number : Class : !
635035 3
! Name : !
ADAM BASHA
+========================================+
! Code ! Description ! Amount !
+========================================+
! 2222 ! Tech.Exam Allow ! 340.00 !
! 3104 ! D A ! 19,524.43 !
! 3107 ! H R A ! 3,984.40 !
! 4113 ! Transport Allow ! 460.00 !
! : !
Net Amount Payable : 24,308.83
! S R Number : Class : !
551820 2
! Name : !
TOM SMITH
+========================================+
! Code ! Description ! Amount !
+========================================+
! 3104 ! D A ! 19,404.41 !
! 3107 ! H R A ! 3,960.60 !
! 4113 ! Transport Allow ! 460.00 !
! : !
Net Amount Payable : 23,825.01
! S R Number : Class : !
550044 3
! Name : !
ROBERT LOUIS
我希望将类似于下面给出的这种格式的每两行合并一次
! S R Number : Class : !
635035 3
我要两行合并如下
! S R Number : 635035 Class : 3 !
而整个结果应该如下:
! S R Number : 635035 Class : 3 !
! Name : ADAM BASHA !
+========================================+
! Code ! Description ! Amount !
+========================================+
! 2222 ! Tech.Exam Allow ! 340.00 !
! 3104 ! D A ! 19,524.43 !
! 3107 ! H R A ! 3,984.40 !
! 4113 ! Transport Allow ! 460.00 !
! Net Amount Payable : 24,308.83 !
! S R Number : 551820 Class : 2 !
! Name : TOM SMITH !
+========================================+
! Code ! Description ! Amount !
+========================================+
! 3104 ! D A ! 19,404.41 !
! 3107 ! H R A ! 3,960.60 !
! 4113 ! Transport Allow ! 460.00 !
! Net Amount Payable : 23,825.01 !
! S R Number : 550044 Class : 3 !
! Name : ROBERT LOUIS !
文件太大,所以我贴了一个样例。这个输出文件似乎将一些行分成两行,比如包含 S R Number, Name and Net Amount Payable
的行。请为此提供解决方案。
已经给出的答案工作正常,唯一的问题是他们处理所有的行,而不是只处理被分割的行。感谢大家。
我已经使用实际示例编辑了我的问题。
这个(不是很优雅)命令应该完成输入文件的工作test
:
awk 'BEGIN{odd=1}
odd{line=[=10=];odd=0;next}
{odd=1;nline=""
for(i=1; i<=length([=10=]);i++){
nline=substr([=10=],i,1)==" " && i <= length(line)? nline""substr(line,i,1) : nline""substr([=10=],i,1)
}
print nline
}' test
输出:
Name : Adam Basha Class : 3
$ cat tst.awk
/^[^[:space:]]/ {
if (NR>1) { print buf }
buf = [=10=]
next
}
{
if (/:/) { sub(/:/," ",buf) }
while ( match([=10=],/[^[:space:]]+/) ) {
buf = substr(buf,1,RSTART-1) substr([=10=],RSTART,RLENGTH) substr(buf,RSTART+RLENGTH)
[=10=] = sprintf("%*s",RSTART+RLENGTH-1,"") substr([=10=],RSTART+RLENGTH)
}
}
END { print buf }
.
$ awk -f tst.awk file
! S R Number : 635035 Class : 3 !
! Name : ADAM BASHA !
+========================================+
! Code ! Description ! Amount !
+========================================+
! 2222 ! Tech.Exam Allow ! 340.00 !
! 3104 ! D A ! 19,524.43 !
! 3107 ! H R A ! 3,984.40 !
! 4113 ! Transport Allow ! 460.00 !
! Net Amount Payable : 24,308.83 !
! S R Number : 551820 Class : 2 !
! Name : TOM SMITH !
+========================================+
! Code ! Description ! Amount !
+========================================+
! 3104 ! D A ! 19,404.41 !
! 3107 ! H R A ! 3,960.60 !
! 4113 ! Transport Allow ! 460.00 !
! Net Amount Payable : 23,825.01 !
! S R Number : 550044 Class : 3 !
! Name : ROBERT LOUIS !
另一种 gawk
使用单字符长度字段的解决方案
$ awk 'BEGIN{OFS=FS=""}
{if(NR%2) split([=10=],p);
else {for(i=1;i<=NF;i++) if($i==" ") $i=p[i];
print}}' file
Name : Adam Basha Class :3
此处假设第二条记录比第一条记录长(如果不是,则将循环结束条件更改为最大长度 (p) 和 NF 或之后追加额外内容。
这可能对你有用 (GNU sed):
sed -r 'N;/\n\s/!{P;D};s/^/\n/;ta;:a;/\n.*\n$/s/\n//g;t;s/\n\n/\n \n/;s/\n(\S)(.*)\n./\n\n/;ta;s/\n.(.*)\n(.)/\n\n/;ta' file
该过程组合所需的行并使用从左到右移动的唯一标记(换行符),比较标记后面的单个字符。如果第一个不是 space 保留它并在其上推进标记。否则,将第一个替换为第二个并将标记推进到它上面。如果标记已到达行尾,则删除标记,但第一行比第二行短时在第一行引入额外的 space 时除外。
这里给出了我的文件的示例输出
! S R Number : Class : !
635035 3
! Name : !
ADAM BASHA
+========================================+
! Code ! Description ! Amount !
+========================================+
! 2222 ! Tech.Exam Allow ! 340.00 !
! 3104 ! D A ! 19,524.43 !
! 3107 ! H R A ! 3,984.40 !
! 4113 ! Transport Allow ! 460.00 !
! : !
Net Amount Payable : 24,308.83
! S R Number : Class : !
551820 2
! Name : !
TOM SMITH
+========================================+
! Code ! Description ! Amount !
+========================================+
! 3104 ! D A ! 19,404.41 !
! 3107 ! H R A ! 3,960.60 !
! 4113 ! Transport Allow ! 460.00 !
! : !
Net Amount Payable : 23,825.01
! S R Number : Class : !
550044 3
! Name : !
ROBERT LOUIS
我希望将类似于下面给出的这种格式的每两行合并一次
! S R Number : Class : !
635035 3
我要两行合并如下
! S R Number : 635035 Class : 3 !
而整个结果应该如下:
! S R Number : 635035 Class : 3 !
! Name : ADAM BASHA !
+========================================+
! Code ! Description ! Amount !
+========================================+
! 2222 ! Tech.Exam Allow ! 340.00 !
! 3104 ! D A ! 19,524.43 !
! 3107 ! H R A ! 3,984.40 !
! 4113 ! Transport Allow ! 460.00 !
! Net Amount Payable : 24,308.83 !
! S R Number : 551820 Class : 2 !
! Name : TOM SMITH !
+========================================+
! Code ! Description ! Amount !
+========================================+
! 3104 ! D A ! 19,404.41 !
! 3107 ! H R A ! 3,960.60 !
! 4113 ! Transport Allow ! 460.00 !
! Net Amount Payable : 23,825.01 !
! S R Number : 550044 Class : 3 !
! Name : ROBERT LOUIS !
文件太大,所以我贴了一个样例。这个输出文件似乎将一些行分成两行,比如包含 S R Number, Name and Net Amount Payable
的行。请为此提供解决方案。
已经给出的答案工作正常,唯一的问题是他们处理所有的行,而不是只处理被分割的行。感谢大家。
我已经使用实际示例编辑了我的问题。
这个(不是很优雅)命令应该完成输入文件的工作test
:
awk 'BEGIN{odd=1}
odd{line=[=10=];odd=0;next}
{odd=1;nline=""
for(i=1; i<=length([=10=]);i++){
nline=substr([=10=],i,1)==" " && i <= length(line)? nline""substr(line,i,1) : nline""substr([=10=],i,1)
}
print nline
}' test
输出:
Name : Adam Basha Class : 3
$ cat tst.awk
/^[^[:space:]]/ {
if (NR>1) { print buf }
buf = [=10=]
next
}
{
if (/:/) { sub(/:/," ",buf) }
while ( match([=10=],/[^[:space:]]+/) ) {
buf = substr(buf,1,RSTART-1) substr([=10=],RSTART,RLENGTH) substr(buf,RSTART+RLENGTH)
[=10=] = sprintf("%*s",RSTART+RLENGTH-1,"") substr([=10=],RSTART+RLENGTH)
}
}
END { print buf }
.
$ awk -f tst.awk file
! S R Number : 635035 Class : 3 !
! Name : ADAM BASHA !
+========================================+
! Code ! Description ! Amount !
+========================================+
! 2222 ! Tech.Exam Allow ! 340.00 !
! 3104 ! D A ! 19,524.43 !
! 3107 ! H R A ! 3,984.40 !
! 4113 ! Transport Allow ! 460.00 !
! Net Amount Payable : 24,308.83 !
! S R Number : 551820 Class : 2 !
! Name : TOM SMITH !
+========================================+
! Code ! Description ! Amount !
+========================================+
! 3104 ! D A ! 19,404.41 !
! 3107 ! H R A ! 3,960.60 !
! 4113 ! Transport Allow ! 460.00 !
! Net Amount Payable : 23,825.01 !
! S R Number : 550044 Class : 3 !
! Name : ROBERT LOUIS !
另一种 gawk
使用单字符长度字段的解决方案
$ awk 'BEGIN{OFS=FS=""}
{if(NR%2) split([=10=],p);
else {for(i=1;i<=NF;i++) if($i==" ") $i=p[i];
print}}' file
Name : Adam Basha Class :3
此处假设第二条记录比第一条记录长(如果不是,则将循环结束条件更改为最大长度 (p) 和 NF 或之后追加额外内容。
这可能对你有用 (GNU sed):
sed -r 'N;/\n\s/!{P;D};s/^/\n/;ta;:a;/\n.*\n$/s/\n//g;t;s/\n\n/\n \n/;s/\n(\S)(.*)\n./\n\n/;ta;s/\n.(.*)\n(.)/\n\n/;ta' file
该过程组合所需的行并使用从左到右移动的唯一标记(换行符),比较标记后面的单个字符。如果第一个不是 space 保留它并在其上推进标记。否则,将第一个替换为第二个并将标记推进到它上面。如果标记已到达行尾,则删除标记,但第一行比第二行短时在第一行引入额外的 space 时除外。