You can also do this with an Ex
command using sed
as an external filter:
:%!sed -n 'h;n;G;h;n;G;h;n;G;p'
This version will ignore (delete) any extra lines beyond a multiple of 4. To keep in the last set of less than 4 lines (reversed), use:
:%!sed -n '$p;h;n;G;$p;h;n;G;$p;h;n;G;p'
The %
here means "Every line in the buffer."
The !
command means "Run the following command with the specified lines as input, and replace the specified lines with the output of the command." (It's called a filter; very handy for such things as sorting, e.g., :%!sort
will sort all the lines in your file; :2,8!sort
will sort lines 2-8, etc.)
sed
is the stream editor tool and is found on all Unix-like systems. The key concepts of sed
used here are the "pattern space" (which by default just contains each line of the input in turn), and the "hold space" (which is where you can stick extra text while using sed
to save it while processing other lines of input).
-n
is an option to the sed
command to suppress its default actions of printing the pattern space (because in this case we only want to print when we explicitly say so.)
$p
in the sed
command means "If you are on the last line of sed
's input, print (the pattern space)."
h
means "stick the current contents of the 'pattern space' in the 'hold space', overwriting whatever's there."
n
means "replace the contents of the 'pattern space' with the next line from the input."
G
means "append to the 'pattern space': a newline followed by the contents of the 'hold space'."
Taken all together, the sed
command stores up four lines of output, reversing them as it stores them, and then prints them. The $p
commands added in the second version ensure that if the last line of the file is reached other than on a multiple of 4 lines, the lines are still printed.
For an alternate, interactive approach still without using any Vim-specific features and also without using an external filter:
:4
to go to the fourth line.
:.m -4 | +3m . | +2m . | +5
to reverse the previous four lines (1-4) and leave your cursor on line 8.
.m -4
moves the current line to just after the line four lines back (leaving the cursor on the moved line).
+3m .
moves the line that is 3 lines after the current line, to just after the current line, leaving the cursor on the moved line. +2m .
of course works the same.
+5
places the cursor five lines down from where it is.
Repeat as desired.
In Vim you can repeat this whole command with @:
, then repeat again with @@
. In POSIX vi
or ex
you would need to insert :.m -4 | +3m . | +2m . | +5
as a line of text, delete it to a named buffer (register), and then execute that named buffer (register).
So in ex
mode, reversing lines interactively using POSIX-specified features only, and starting with 17 lines of text:
Entering Ex mode. Type "visual" to go to Normal mode.
:0a # Append following text after "line 0" (i.e. insert at start of file).
.m -4 | +3m . | +2m . | +5
. # End text insertion
:d k # Delete that line to register k
line1 # This is a printout of the current line
:4 # Move to line 4
line4
:@k # Execute register k to reverse lines 1-4
line8
:@@ # Execute register k again
line12
:@@ # Execute register k again
line16
:@@ # Execute register k again
line17
:%p # Print the whole buffer (just to see what was done)
line4
line3
line2
line1
line8
line7
line6
line5
line12
line11
line10
line9
line16
line15
line14
line13
line17
:wq # Save and quit
Further reading: