tulamba
tulamba

Reputation: 131

Moving matching lines in a text file using sed

I am trying to follow the post

How to move specified line in file to other place with regexp match (bash script)?

to my example file

asdasd0
-SRC_OUT_DIR = /a/b/c/d/e/f/g/h
asdasd2
asdasd3
asdasd4
DEFAULTS {
asdasd6

The final output should look like

asdasd0
asdasd2
asdasd3
asdasd4
DEFAULTS {
-SRC_OUT_DIR = /a/b/c/d/e/f/g/h
asdasd6

I have tried the following

sed "/-SRC_OUT_DIR.*/d;/DEFAULTS { /a"$(sed -n '/-SRC_OUT_DIR.*/p' test.txt)  test.txt`

but it is not working. I get the following output

sed:can't read =: No such file or directory
sed:can't read "/a/b/c/d/e/f/g": No such file or directory
asdasd0
asdasd2
asdasd3
asdasd4
DEFAULTS {
-SRC_OUT_DIR
asdasd6

I am also wondering why can't I use \1, \2 to print the line that needs to be moved. I tried that but it prints nothing. How would I write a sed command if I need to move multiple matching lines to different places in the file?

Upvotes: 1

Views: 2783

Answers (2)

Benjamin W.
Benjamin W.

Reputation: 52122

You could store the matching line in the hold space, delete it and then append the hold space to the line after which you want to insert:

$ sed '/^-SRC_OUT_DIR/{h;d;};/^DEFAULTS {/G' infile
asdasd0
asdasd2
asdasd3
asdasd4
DEFAULTS {
-SRC_OUT_DIR = /a/b/c/d/e/f/g/h
asdasd6

Upvotes: 4

kvantour
kvantour

Reputation: 26471

While you ask a sed solution I would propose to use awk for this. Using an ugly nesting of a multitude of sed commands is not really recommended. Especially because you read your file twice.

Here is an awk

awk '/SRC_OUT_DIR/{t=$0;next}1;/DEFAULTS/{print t}' file

How does it work?

awk will read your file line by line. Per line, it will do the following three commands one after the other:

  1. /SRC_OUT_DIR/{t=$0;next}: if the line contains a substring matching SRC_OUT_DIR, then store the line in a variable t and move to the next line (don't execute 2 and 3)
  2. 1: default action: print the line
  3. /DEFAULTS/{print t}: if the current line contains the substring DEFAULTS, print the line stored in variable t

If you have multiple lines to move (this only moves downwards):

awk '/pattern1/ {t[1]=$0;next}
     /pattern2/ {t[2]=$0;next}
     /pattern3/ {t[3]=$0;next}
     /target3/ { print t[3] }
     1
     /target1/ { print t[1] }
     /target2/ { print t[2] }' file

note that pattern3 will be printed before target3.

Upvotes: 3

Related Questions