Use head
and tail
, plus some simple bash arithmetic expansion. You also need either tac
or wc
:
First, create a minimum reproducible example for the input file. Set n
- the number of lines from the end of the file to rotate to the beginning:
n = 2
perl -le 'print "line$_" for 1..7' > in_file
cat in_file
Prints:
line1
line2
line3
line4
line5
line6
line7
Method 1: Rotate with tail
and head
, plus wc
.
This is slightly less complex than method 2, and uses wc -l ... - $n
to compute the number of lines for the head
to print. I prefer this method because the programmer's intentions are more clear here. It is also faster, see benchmarks below.
( tail -n $n in_file ; head -n $(( $( wc -l <in_file ) - $n )) in_file ) > out_file
Prints:
line6
line7
line1
line2
line3
line4
line5
Method 2: Rotate with tail
and head
, plus tac
.
Here,
tac
: write the lines in reverse order into STDOUT,
tail -n +3
: write the above lines in reverse order starting from line 3 from the end of the original file (lines 1-2 are thus not written),
tac
: use tac
a total of twice, to reverse the reverse order of lines, in order to write the lines in the original order.
( tail -n $n in_file ; tac in_file | tail -n +$(( $n+1 )) | tac ) > out_file
Benchmarks:
Method 1 using wc
is substantially faster that method 2 using tac
twice:
perl -le 'print "line$_" for 1..1e7' > in_file
n=2
for i in `seq 1 10` ; do
( time ( tail -n $n in_file ; head -n $(( $( wc -l <in_file ) - $n )) in_file ) > out_file ) 2>&1 | grep real
done
Prints:
real 0m0.539s
real 0m0.538s
real 0m0.545s
real 0m0.566s
real 0m0.540s
real 0m0.532s
real 0m0.561s
real 0m0.534s
real 0m0.530s
real 0m0.520s
for i in `seq 1 10` ; do
( time ( tail -n $n in_file ; tac in_file | tail -n +$(( $n+1 )) | tac ) > out_file ) 2>&1 | grep real
done
Prints:
real 0m0.855s
real 0m0.884s
real 0m0.916s
real 0m0.829s
real 0m0.838s
real 0m0.873s
real 0m0.877s
real 0m0.862s
real 0m0.835s
real 0m0.867s
I ran this using MacBook Pro with macOS v.10.14.6, running:
bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)