4

I have the file

Line 1
Line 2 MATCH
Line 3
Line 4
Line 1
Line 2 MATCH
Line 3
Line 4

And I want to swap the line with "MATCH" and "Line 1" for every case. I tried to search in other questions, but those move the line with the match to the last line and I don't understand so well the code to remake my version for a final output like:

Line 2 MATCH
Line 1
Line 3
Line 4
Line 2 MATCH
Line 1
Line 3
Line 4
  • Is the line with "MATCH" always line two, hence to be swapped with the line before it? – Sparhawk Feb 17 '19 at 20:53
  • @Sparhawk Yes, it is. – TheAsker Feb 17 '19 at 20:55
  • @don_crissti but in the answer provided there, they only swap the line N with the line below. For swap line N with the line above, they swap the Line N-1 with the line below. There is some way to swap with the line above based on a pattern? – TheAsker Feb 17 '19 at 21:11

5 Answers5

4

Using sed with a N;P;D cycle:

sed -e '$!N;s/\(Line 1\)\(\n\)\(.*MATCH.*\)/\3\2\1/;t' -e 'P;D' infile

This will swap only if the line with MATCH is preceded by Line 1: the t without label branches to the end of script if successful and so it avoids another swap if any Line 1 is followed by consecutive lines with MATCH. Adjust the regex for any leading/trailing blanks.

don_crissti
  • 82,805
3

If the idea is to swap the MATCH line with the immediately preceding one, then something like this would do:

$ awk '!/MATCH/ { if (NR > 1) print prev; prev=$0} 
        /MATCH/ {print $0;} 
        END {print prev}' < file
Line 2 MATCH
Line 1
Line 3
Line 4
Line 2 MATCH
Line 1
Line 3
Line 4

The script holds the previous line in prev, printing and updating it on the non-matching lines. On lines matching the pattern, it prints the current line, leaving the previous in the variable to be printed next.

Special cases for the first line (NR==1) when there's no previous line to print, and for the END when we print the held line.

ilkkachu
  • 138,973
3

Using ed:

$ printf 'g/MATCH/m-2\n,p\n' | ed -s file
Line 2 MATCH
Line 1
Line 3
Line 4
Line 2 MATCH
Line 1
Line 3
Line 4

The m command moves the current line after to the subsequent target address. Here, we find all lines matching MATCH (it's the g in front of the regular expression that makes this a "global" operation), and for each line move it one line up (to "after the line two lines up"). The effect is that the MATCH lines swap places with the immediately preceding lines.

The final ,p in the editing script just displays the modified editing buffer. This could be changed to something like wq to write the changed editing buffer back to the original file.

Note that using ed for editing files might look neat, but is not recommended for large files as the whole file is read into memory.

Kusalananda
  • 333,661
1

Using sed editor, we can swap two lines one of which contains Match keyword with the one preceding it.

 $ sed -e '
       /MATCH/!{
         x;1!p;$!d;g;q
       }
       $G
   '  input.txt

 Line 2 MATCH
 Line 1
 Line 3
 Line 4
 Line 2 MATCH
 Line 1
 Line 3
 Line 4
-1

sed "s/line 2 match//g"|sed "s/line 1/line 2 match\n&/g"

Above command worked fine