AWK or sed way to paste non-adjacent lines

雨燕双飞 提交于 2020-12-06 06:36:49

问题


$ cat file
aaa bbb ccc
ddd eee
jjj kkk lll
mmm
nnn ooo ppp

The following AWK command will paste the 'mmm' line at the end of the 'ddd eee' line. Is there a simpler way to do this using AWK or sed?

$ awk 'FNR==NR {if (NR==4) foo=$0; next} FNR==2 {print $0" "foo; next} FNR==4 {next} 1' file file
aaa bbb ccc
ddd eee mmm
jjj kkk lll
nnn ooo ppp

To clarify: I want to paste line 4 at the end of line 2 in this particular file, with a single space between the 'ddd eee' and the 'mmm'. That's the task. Is there an AWK or sed solution that's simpler than the one I came up with?


回答1:


This can be done in sed using the hold space:

sed '2{N;h;N;s/\n.*\n/ /;p;g;D;}' file
  • 2{...} Run the enclosed commands on line two.
  • N;h;N Read next two lines into the pattern space, holding the first two.
  • s/\n.*\n/ / Substitute a space for the middle line.
  • p;g;D Print the pasted lines, load the hold space, and delete the first line (leaving the one that was removed by the previous substitute).

or using captures (\(...\)) & back-references (\1, \2, etc.):

sed '2{N;N;s/\(\n.*\)\n\(.*\)/ \2\1/;}' file
  • 2{...} Run the enclosed commands on line two.
  • N;N Read next two lines into the pattern space.
  • s/\(\n.*\)\n\(.*\)/ \2\1/ Swap the third and fourth line, joining the first and third lines.
    • \(\n.*\) Capture the third line, including the leading newline.
    • \n\(.*\) Capture the fourth line, excluding the leading newline.
    • / \2\1/ Replace the matched portion (the third & fourth lines) with a space, followed by the second, and then the first capture groups.



回答2:


This meets the letter of the amended problem statement — it prints line 1, appends line 4 after the content of line 2 as line 2, then prints line 3, and then prints line 5 and beyond:

awk 'NR == 1 || NR >= 5 { print; next }
     NR == 2 { save2 = $0 }
     NR == 3 { save3 = $0 }
     NR == 4 { print save2, $0; print save3 }' file

It's simpler than the code in the question in that it only scans the file once.

The output:

aaa bbb ccc
ddd eee mmm
jjj kkk lll
nnn ooo ppp



回答3:


Solution in TXR:

$ txr -c '@line1
@line2
@line3
@line4
@(data rest)
@(output)
@line1
@line2 @line4
@line3
@  (repeat)
@  rest
@  (end)
@(end)' file
aaa bbb ccc
ddd eee mmm
jjj kkk lll
nnn ooo ppp



回答4:


This is simpler:

$ awk 'FNR==NR {if (NR==4) foo=$0; next} FNR==2{$0=$0" "foo} FNR!=4' file file
aaa bbb ccc
ddd eee mmm
jjj kkk lll
nnn ooo ppp

Other solutions might be faster or use less memory but they won't be simpler.



来源:https://stackoverflow.com/questions/39187856/awk-or-sed-way-to-paste-non-adjacent-lines

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!