Quantcast
Channel: How can I reverse the order of lines in a file? - Stack Overflow
Viewing all articles
Browse latest Browse all 26

Answer by dosentmatter for How can I reverse the order of lines in a file?

$
0
0

You can do it with vimstdin and stdout. You can also use ex to be POSIX compliant. vim is just the visual mode for ex. In fact, you can use ex with vim -e or vim -E (improved ex mode).vim is useful because unlike tools like sed it buffers the file for editing, while sed is used for streams. You might be able to use awk, but you would have to manually buffer everything in a variable.

The idea is to do the following:

  1. Read from stdin
  2. For each line move it to line 1 (to reverse). Command is g/^/m0. This means globally, for each line g; match the start of the line, which matches anything ^; move it after address 0, which is line 1 m0.
  3. Print everything. Command is %p. This means for the range of all lines %; print the line p.
  4. Forcefully quit without saving the file. Command is q!. This means quit q; forcefully !.
# Generate a newline delimited sequence of 1 to 10$ seq 1012345678910# Use - to read from stdin.# vim has a delay and annoying 'Vim: Reading from stdin...' output# if you use - to read from stdin. Use --not-a-term to hide output.# --not-a-term requires vim 8.0.1308 (Nov 2017)# Use -E for improved ex mode. -e would work here too since I'm not# using any improved ex mode features.# each of the commands I explained above are specified with a + sign# and are run sequentially.$ seq 10 | vim - --not-a-term -Es +'g/^/m0'+'%p'+'q!'10987654321# non improved ex mode works here too, -e.$ seq 10 | vim - --not-a-term -es +'g/^/m0'+'%p'+'q!'# If you don't have --not-a-term, use /dev/stdinseq 10 | vim -E +'g/^/m0'+'%p'+'q!' /dev/stdin# POSIX compliant (maybe)# POSIX compliant ex doesn't allow using + sign to specify commands.# It also might not allow running multiple commands sequentially.# The docs say "Implementations may support more than a single -c"# If yours does support multiple -c$ seq 10 | ex -c "execute -c 'g/^/m0' -c '%p' -c 'q!' /dev/stdin# If not, you can chain them with the bar, |. This is same as shell# piping. It's more like shell semi-colon, ;.# The g command consumes the |, so you can use execute to prevent that.# Not sure if execute and | is POSIX compliant.seq 10 | ex -c "execute 'g/^/m0' | %p | q!" /dev/stdin

How to make this reusable

I use a script I call ved (vim editor like sed) to use vim to edit stdin. Add this to a file called ved in your path:

#!/usr/bin/env shvim - --not-a-term -Es "$@"+'%p | q!'

I am using one + command instead of +'%p'+'q!', because vim limits you to 10 commands. So merging them allows the "$@" to have 9 + commands instead of 8.

Then you can do:

seq 10 | ved +'g/^/m0'

If you don't have vim 8, put this in ved instead:

#!/usr/bin/env shvim -E "$@"+'%p | q!' /dev/stdin

Viewing all articles
Browse latest Browse all 26

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>