Reputation: 51
How can I move last n lines of a text file to the top without knowing number of lines of the file? Is it possible to achieve this with single command line (with sed
for example)?
From:
...
a
b
c
d
To:
a
b
c
d
...
Upvotes: 4
Views: 2544
Reputation: 3470
Using vim's ex mode is even simpler: (inspired by this answer)
vim - -esc '$-3,$m0|%p|q!' --not-a-term # when processing a pipe
vim file.txt -esc '$-3,$m0|%p|q!' --not-a-term # when processing a file to stdout
vim file.txt -esc '$-3,$m0|wq' --not-a-term # when editing a file inline
This will move last 4 lines (last line + 3 lines before the last line) to top. Change 3
to your desired number.
A MWE:
seq 10 | vim - '-esc$-3,$m0|%p|q!' --not-a-term
Output:
7
8
9
10
1
2
3
4
5
6
You may find it hard if the input source is from pipe. In this case, you can use
awk '{a[NR-1]=$0}END{for(i=0;i<NR;++i)print(a[(i-4+NR)%NR])}'
This will store all lines in memory (which may be an issue) and then output them. Change 4
in the command to see different results.
Display the last n lines and then display the rest:
tail -n 4 file; head -n -4 file
From man head
:
-n, --lines=[-]NUM
print the first NUM lines instead of the first 10; with the leading '-', print all but the last NUM lines of each file
tail -n 4
will display the last 4 lines of a file.
If you wish to pipe this data, you need to put them together like this:
( tail -n 4 file; head -n -4 file ) | wc
Or maybe you can use vim to edit file inline:
vim +'$-3,$m0' +'wq' file
The +
option for vim will run the (Ex) command following it. $-3,$m0
means move lines between 3 lines above the last line and the last line to the beginning of the file. Note that there should be no space between +
and the command.
Or using commands in vim normal mode:
vim +'norm G3kdGggPZZ' file
G
go to file end; 3k
move up 3 lines; dG
deletes to file end; gg
go to file top; P
pastes the deleted lines before this line; ZZ
saves and quits.
Upvotes: 6
Reputation: 7831
It is trivial to do with ed
Move the last 30
lines on top of the file.
printf '%s\n' '30,$m0' ,p Q | ed -s file.txt
Move 10 to 50 lines on top of the file.
printf '%s\n' '10,50m0' ,p Q | ed -s file.txt
Move 1 to 10 to the last line/buffer.
printf '%s\n' '1,10m$' ,p Q | ed -s file.txt
Move 40 to 80 at the last line/buffer
printf '%s\n' '40,80m$' ,p Q | ed -s file.txt
Line address 0
is the first and m
means move
$
is the last line of the buffer/file.
Change Q
to w
to actually edit the file.txt
Upvotes: 0
Reputation: 58488
This might work for you (GNU sed):
sed '$!H;1h;$!d;G' file
Append every line but the last to the hold space and then append the hold space to the the last line.
Upvotes: 1