How do I reverse selected lines order in Vim?

98

22

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?

Jichao

Posted 2010-09-17T23:57:13.297

Reputation: 5 245

2

Duplicate on [SO]: How to flip a visual selection in vim?

– Palec – 2014-12-27T14:51:01.703

1

Related: Reverse all lines @ Vim Wikia

– Palec – 2014-12-27T14:53:04.347

1:command! -bar -range=% Reverse <line1>,<line2>global/^/m<line1>-1 https://vi.stackexchange.com/a/2107/10254 – qeatzy – 2017-12-19T08:52:01.663

Answers

90

To reverse all the lines in a file,

:g/^/m0

For an explanation see

:help 12.4

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

garyjohn

Posted 2010-09-17T23:57:13.297

Reputation: 29 085

13Great 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 – 2013-12-06T19:25:52.067

74

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

Posted 2010-09-17T23:57:13.297

Reputation: 841

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 – 2018-03-12T13:27:44.040

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 – 2018-09-26T13:23:57.807

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 – 2019-08-10T03:58:04.603

4To select the lines, use shift+v to enter visual line mode, then j to add lines to the selection. – wisbucky – 2014-05-21T21:46:23.840

36

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

Posted 2010-09-17T23:57:13.297

Reputation: 461

1Genius. Never thought of using ! commands for this type of visual line manipulation. – Charlie Dalsass – 2019-05-15T15:20:57.607

3Excellent! So to provide 'tac' under OS X: alias tac='tail -r' – Brent Faust – 2013-12-06T19:27:42.543

4You can also brew install coreutils and use gtac. – Andrew Marshall – 2014-04-11T03:25:49.650

4

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

Posted 2010-09-17T23:57:13.297

Reputation: 550

This should be the accepted answer IMO. Most generally useful and I don't have to remember :'<,'>g/^/m'< :) – Eliot – 2017-01-11T22:01:38.570

1@Eliot, thanks! :) (I added a bit of 'bonus content'. ;) ) – Aaron Thoma – 2017-01-12T18:14:25.737

How can I say selection start -1 in this case? Because the move starts at this point. – SergioAraujo – 2018-02-17T10:31:47.173

@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 – 2018-02-17T15:30:10.343

3

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

Posted 2010-09-17T23:57:13.297

Reputation: 359

4You can use the '< instead of entering the line number manually. Just start the selection one line earlier and execute :'<,'>g/^/m'<. – Palec – 2016-09-15T09:06:31.097

1

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

:3,6g/^/m2

SergioAraujo

Posted 2010-09-17T23:57:13.297

Reputation: 211

1You 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 – 2018-02-17T15:47:13.440