Reputation: 123
I would like to know how to change the position of a line in a file (preferably using sed). For example, consider the file that contains
goal identifier statement
let statement 1
let statement 2
forall statement
other statements
I would like to be able to do this
goal identifier statement
forall statement
let statement 1
let statement 2
other statements
where I change the position of the forall line and bring it after the goal line. forall and goal are regexps that can be used to identify the lines.
Upvotes: 3
Views: 2830
Reputation: 11504
A less terrible way using vim to find a line in $FILENAME using regex $REGEX_EXPRESSION and move that line to $LINE_NUMBER:
vim -c "g:$REGEX_EXPRESSION:m$LINE_NUMBER" -cwq "$FILENAME"
explanation: -c
is command in vim, so it goes to the first line that matches that regex and then moves it to the line number specified, and then does the command wq
(or write and quit).
Upvotes: 1
Reputation: 2025
sed -r '/goal/{ # if match "goal" line
:X # this is a lable for branch command
N # append next line
/forall[^\n]*$/{ # if match "forall" line move to "goal" line below
s#^([^\n]*)(.*)(\n[^\n]*)$#\1\3\2#
b # after move finished branch to end
}
bX # branch to :X for appending next line
}' file
goal identifier statement
forall statement
let statement 1
let statement 2
other statements
Upvotes: 0
Reputation: 204578
sed is for simple substitutions on individual lines, that is all. For anything else you should use awk for every desirable attribute of software (clarity, simplicity, portability, etc.:
$ awk 'NR==FNR{if (/forall/) {f=FNR; v=$0} next} FNR!=f; /goal/{print v} ' file file
goal identifier statement
forall statement
let statement 1
let statement 2
other statements
Upvotes: 0
Reputation: 8174
you can try, for move line 4
to line 2
, I want to move line A
to line B
, where A>B
sed -n '2{h; :a; n; 4{p;x;bb}; H; ba}; :b; p' file
or A<B
sed -n '2{h; d}; 4{p; x;}; p' file
you get, in first case: move line 4
to line 2
goal identifier statement
forall statement
let statement 1
let statement 2
other statements
you get, in second case: move line 2
to line 4
goal identifier statement
let statement 2
forall statement
let statement 1
other statements
Explanation
sed -n ' #silent option ON
2{ #if is line 2
h #Replace the contents of the hold space with the contents of the pattern space
:a #label "a"
n #fetch the next line
4{ #if is line 4
p #print line 4
x #Exchange the contents of the hold and pattern spaces
bb #goto "b"
}
H #appends line from the pattern space to the hold space, with a newline before it.
ba #goto "a"
}
:b #Label "b"
p #print
' file
EDIT
If You want use regex
for identify the lines, you can modify first command
sed -n '/goal/{p;n;h;:a;n;/forall/{p;x;bb};H;ba};:b;p' file
Upvotes: 6
Reputation: 5768
$ cat r.awk
BEGIN {
forall_re = "^forall" # examples of regexps
goal_re = "^goal"
}
function tag(l) { # tag a line
if (l ~ goal_re ) return "goal"
else if (l ~ forall_re) return "forall"
else return "rest"
}
{ # store entire file in array; give a tag to every line
lines[NR] = $0
tags[NR] = tag($0)
}
function swap0(a, i, j, tmp) {
tmp = a[i]; a[i] = a[j]; a[j] = tmp
}
function swap(i, j) {
swap0(lines, i, j); swap0(tags, i, j)
}
function rise(i) {
# TODO: add error check
while (i - 1 > 0 && tags[i - 1] != "goal") {
swap(i, i - 1); i--
}
}
function process( i) {
for (i = 1; i <= NR; i++)
if (tags[i] == "forall") rise(i)
}
function dump( i) { # print the array
for (i = 1; i <= NR; i++)
print lines[i]
}
END {
process()
dump()
}
An example of input file
$ cat r.txt
goal identifier statement
let statement 1
let statement 2
forall statement A
other statements
goal identifier statement
let statement 1
let statement 2
forall statement B
other statements
Usage:
$ awk -f r.awk r.txt
goal identifier statement
forall statement A
let statement 1
let statement 2
other statements
goal identifier statement
forall statement B
let statement 1
let statement 2
other statements
Upvotes: 1