133

For example, if I have four lines as follows:

the first line
the second line
the third line
the fourth line

I want to reverse them to

the fourth line
the third line
the second line
the first line

How could I do this in Vim?

Peter Mortensen
  • 12,090
  • 23
  • 70
  • 90
Jichao
  • 7,145
  • 12
  • 52
  • 62
  • 2
    Duplicate on [SO]: [How to flip a visual selection in vim?](http://stackoverflow.com/q/5561249/2157640) – Palec Dec 27 '14 at 14:51
  • 1
    Related: [Reverse all lines @ Vim Wikia](http://vim.wikia.com/wiki/Reverse_all_lines) – Palec Dec 27 '14 at 14:53
  • 2
    `:command! -bar -range=% Reverse ,global/^/m-1` https://vi.stackexchange.com/a/2107/10254 – qeatzy Dec 19 '17 at 08:52

6 Answers6

133

To reverse all the lines in a file,

:global/^/move 0

Abbreviated:

:g/^/m0

For an explanation see

:help 12.4

which also shows how to reverse just a range of lines.

icc97
  • 577
  • 5
  • 20
garyjohn
  • 34,610
  • 8
  • 97
  • 89
  • 16
    Great tip on the exact help section! To summarize: 1. set a marker at the last line you want reverse (I name the marker 'a' using `ma`), 2. move cursor to the first line of the block, 3. type `:'a,.g/^/m 'a` – Brent Faust Dec 06 '13 at 19:25
  • 1
    [`:help 12.4`](http://vimdoc.sourceforge.net/htmldoc/usr_12.html#12.4). – young_souvlaki Apr 03 '22 at 22:57
109

Select the desired lines, hit !, and in the resulting prompt pipe the lines through tac a la :'<,'>!tac. See man tac for more details.

Rhys Ulerich
  • 1,199
  • 1
  • 7
  • 4
  • 4
    To select the lines, use `shift+v` to enter visual line mode, then `j` to add lines to the selection. – wisbucky May 21 '14 at 21:46
  • I can confirm that this works in windows with `gvim`, as well! Otherwise, you have to use absolute line numbers (maybe you can use relative, but you have to be careful) with the `:g/^/m0` (which is also really hard to remember) ... So, essentially, tac should be with vim no matter what platform you're on, BUT it's not 100% vimscript, BUT who cares :P – dylnmc Mar 12 '18 at 13:27
  • tac isn't fully-native vim handling, but, the 'm'ove command takes a line number and that's not always reasonable. I often use a mark as part of a range, so `:.,'a!tac` works with minimal effort. – studog Sep 26 '18 at 13:23
  • After using `shift+v`, you can use `}` to reach up to the next paragraph, or empty vertical space. Also, `man tac: concatenate and print files in reverse`. – nilon Aug 10 '19 at 03:58
  • This is so money!!! – young_souvlaki Apr 03 '22 at 23:05
  • 2
    (Hitting `!` autofills `:'<'>!` when there is a selection.) – young_souvlaki Aug 25 '22 at 20:20
  • Also great with `vip` to select the current paragraph, followed by `!` which automatically inserts `:'<,'>!` followed by `tac`. In short what you end up tipping to reverse the current paragraph is `vip!tac`. – Paul Rougieux Feb 20 '23 at 14:39
44

On Mac OS X, tac does not exist, but you can use tail -r to the same effect:

:%!tail -r

This also works nicely for visual mode:

:'<,'>!tail -r

Excerpt from tail(1)'s manpage:

The -r option causes the input to be displayed in reverse order, by line. Additionally, this option changes the meaning of the -b, -c and -n options. When the -r option is specified, these options specify the number of bytes, lines or 512-byte blocks to display, instead of the bytes, lines or blocks from the beginning or end of the input from which to begin the display. The default for the -r option is to display all of the input.

Thomas Perl
  • 549
  • 4
  • 4
7

For those more comfortable with Visual mode:
1. Identify the line number above the selection you want flipped using :set nu.
2. Shift-V to highlight selection you want flipped (visual mode).
3. :g/^/m <Line number from step 1>.

Note that in visual mode it will automatically show up as :'<,'>g/^/m <Line number> when you type in the command from 3.

This command works by moving the selection one line at a time into the line number that you give it. When the second item gets pushed into the line number given, it pushes the first down to line number + 1. Then the third pushes the first and second down and so on until the entire list has been pushed into the single line number resulting in a reverse ordered list.

horta
  • 419
  • 4
  • 9
  • 7
    You can use the `'<` instead of entering the line number manually. Just start the selection one line earlier and execute `:'<,'>g/^/m'<`. – Palec Sep 15 '16 at 09:06
7

A command :Rev[erse] and optional mappings for your vimrc, so you don't have to remember and perform the non-obvious steps of this recipe:

" Reverse the lines of the whole file or a visually highlighted block.
    " :Rev is a shorter prefix you can use.
    " Adapted from http://tech.groups.yahoo.com/group/vim/message/34305
command! -nargs=0 -bar -range=% Reverse
    \       let save_mark_t = getpos("'t")
    \<bar>      <line2>kt
    \<bar>      exe "<line1>,<line2>g/^/m't"
    \<bar>  call setpos("'t", save_mark_t)

nmap <Leader>r :Reverse<CR>
xmap <Leader>r :Reverse<CR>

(:xmap maps for Visual but not Select mode, as :help mapmode-x advises for mapping printable characters.)

(Based on: http://tech.groups.yahoo.com/group/vim/message/34305 )

Aaron Thoma
  • 690
  • 8
  • 16
  • This should be the accepted answer IMO. Most generally useful and I don't have to remember `:'<,'>g/^/m'<` :) – Eliot Jan 11 '17 at 22:01
  • 1
    @Eliot, thanks! :) (I added a bit of 'bonus content'. ;) ) – Aaron Thoma Jan 12 '17 at 18:14
  • How can I say selection start -1 in this case? Because the move starts at this point. – SergioAraujo Feb 17 '18 at 10:31
  • @SergioAraujo: Is something like `:-1,+1Rev` what you are looking for? Know that you can visually select the range you want to reverse, e.g.: `V7j:Rev`. If that doesn’t answer your question, I haven’t understood it, so you’d need to elaborate or rephrase it for me. – Aaron Thoma Feb 17 '18 at 15:30
3

Let' say you are at the line 3, hence we have a range 3 to 6. Just type.

:3,6g/^/m2
SergioAraujo
  • 251
  • 3
  • 6
  • 1
    You can leave the current line’s number implicit: With the cursor on your range’s first line, you can shorten to `:,6g/^/m2`; or when on the range’s last line: `:3,g/^/m2`; and `:3,6g/^/m2` works from anywhere in the file. – Aaron Thoma Feb 17 '18 at 15:47