You can do it with vim
stdin
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:
- Read from stdin
- For each line move it to line 1 (to reverse). Command is
g/^/m0
. This means globally, for each lineg
; match the start of the line, which matches anything^
; move it after address 0, which is line 1m0
. - Print everything. Command is
%p
. This means for the range of all lines%
; print the linep
. - Forcefully quit without saving the file. Command is
q!
. This means quitq
; 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