Ever wish you could simply apply a vim command to every line in a command output automatically? If you use vim as your primary editor, this is likely much much easier than having to look up sed commands every time you filter a command output.
E.g., cat file.txt | vims -l 'f|d$'
will go through every line, and run "f|d$",
which is the vim command for deleting every character after "|".
See below for many other useful features.
- Download the file
vims
- Put this file somewhere on your
PATH
environment variable, such as/usr/bin
or$HOME/.local/bin
- Make it executable with
chmod +x vims
. That's it!
... | vims [...]
- (default)
-t [EX_CMD]
Ex mode. Works as if you typed ":" in vim. -s [CMD]
Simple command mode. Starts on the first line in command mode (e.g.,x
deletes a char).-l [CMD]
Line command mode. Runs the command on every line.-e [REGEX] [CMD]
Exe mode. Runs the command on every line matchingREGEX
(uses vim regex).-r [REGEX] [CMD]
Inverse exe mode. Runs the command on every line not matchingREGEX
(uses vim regex).-n
quiet. Don't print lines to stdout. You will then have to use:p
command to print manually.-h
help. Print this documentation.
Note that for commands, you can write \<esc>
to hit the escape key, or \<c-o>
to hit ctrl-O.
{command} | vims [-n|--quiet]
[-e|--exe-mode] [-r|--inverse-exe-mode]
[-s|--simple-mode] [-l|--line-exe-mode]
[-t|--turn-off-mode]
[-h|--help]
[ <args>... ]
Call vims
on piped input, providing a list of arguments that you
would use in vim command-line mode. All lines not deleted are printed
by default, but you can turn this off with a -n|--quiet
flag.
Trigger "exe" mode using the -e|--exe-mode
flag, which creates macros
for '%g/$1/exe "norm $2"'
(see the power of :g
),
where $1
is the first arg of a pair,
and $2
is the last arg of a pair. This lets you type non-text characters,
like \<esc>
, \<c-o>
, etc.
Likewise, -l|--line-exe-mode
translates to %g/.*/exe "norm$1"
, meaning
it executes a command on ALL lines.
Inverse exe mode is done with the -r|--inverse-exe-mode
flag, which
does the same as exe mode, but only on lines NOT matching the regex.
Use simple mode with the -s|--simple-mode
flag, which is as vanilla
as it gets. This translates every passed argument to: exe "norm $1"
, meaning
that you can run commands just like you opened the editor, starting
at line 1. Use the same backslashes (\<enter>
) as you do for exe mode.
Modes are activated for all the proceeding args. You can switch
modes partway, by calling the flag for the other mode you want, or you
can turn off any activated mode with -t|--turn-off-mode
.
Delete lines 10-15, and print the remainder:
cat myfile.txt | vims '10,15d'
10,15
- A range from 10-15 - see:help :range
in vim for a huge number of options.d
- The delete (from ex) command - see:help :d
in vim.
Delete blank lines, then lower-case everything:
cat mylog.log | vims -e '^\s*$' 'dd' '.' 'Vu'
-e
- Turn on exe mode^\s*$
- Line only containing whitespacedd
- Delete it..
- Line containing anything (Every pair of arguments triggers a newexe
command)Vu
- Select the line, then lower-case all alphabetical characters
Or, with line exe mode (a shorthand for .*
):
cat mylog.log | vims -e '^\s*$' 'dd' -l 'Vu'
-l
- Turn off exe mode, turn on line exe mode
Add a comment (#
) on every line NOT containing foo:
cat script.sh | vims -r 'foo' 'A # Comment'
-r
- Work on all lines not matching regexfoo
- Match all lines with the word "foo"A # Comment
- At the end of the line, type " # Comment"
Delete all modifications to files in a git repo:
git status | vims '1,/modified/-1d' '$?modified?,$d' -l 'df:dw' | xargs git checkout --
git status
- View which files are modifiedvims
- Start vims in normal mode1,/modified/-1d
- Delete all lines up to the first line with "modified"$?modified?+1,$d
- Delete all lines from below the last line with "modified"-l
- Turn on line exe mode (execute a command on each line)df:dw
- Delete until the ":", then delete the white spacexargs git checkout --
- Pass all the filenames togit checkout --
Move all Python classes to the bottom of a file:
cat myscript.py | vims -e '^class' 'V/^\\S\<enter>kdGp'
'^class' 'V/^\\S\<enter>kdGp'
becomes'%g/^class/exe "norm V/^\S\<enter>kdGp"'
%g/^class/
- Every line starting with "class"exe
- Execute the following, including escaped sequences (so you can call\<c-o>
to mean Ctrl-o)norm V/^\S\<enter>kdGp
Enter normal mode, visual select to the next zero-indentation line, move up a line, delete, paste it at the bottom
Only print the last 6 lines (just like tail)
cat txt | vims -n '$-5,$p'
-n
- Don't print all lines automatically$-5,$
- A range extending from 6th last line to the last linep
- Print
Replace all multi-whitespace sequences with a single space:
cat txt | vims '%s/\s\+/ /g'
Which can also be done in exe mode:
cat txt | vims -e '.' ':s/\\s\\+/ /g\<enter>'
Note the double back-slashes needed (only in the second string of a pair in an exe command!)
when you are typing a character like \s
, but not like \<enter>
.
Resolve all git conflicts by deleting the changes on HEAD (keep the bottom code):
cat my_conflict.cpp | vims -e '^=======$' 'V?^<<<<<<< \<enter>d' -t '%g/^>>>>>>> /d'
-e
- Turn on exe mode^=======$
- Match the middle bit of a git conflictV?^<<<<<<< \<enter>d
- Highlight the line, backward search to the top of the conflict, delete it.-t
- Turn off exe mode%g/^>>>>>>> /d
- Delete remaining conflict lines
Uncomment all commented-out lines (comment char: #
)
cat script.sh | vims -e '^\s*#' '^x'
^\s*#
- Work on lines with whitespace followed by a comment char, followed by anything^x
- Go to the first non-whitespace character, and delete it
Delete the first word of each line and put it at the end:
cat script.sh | vims -e '^[A-Za-z]' '\"kdwA \<esc>\"kp'
^[A-Za-z]
- Only work on lines that start with an alphabetical character\"kdw
- Delete the word under the cursor and put it in registerk
A \<esc>
- Start insert mode at front of line, type a space, hit escape key\"kp
- Paste from the registerk
Run a super-vanilla long chain of commands in simple mode, starting from line 1 of a file:
cat python.py | vims -s '/^class\<enter>O# This class broke\<esc>Go\<enter># This file broke'
/^class\<enter>
- Find the first class, and go to itO# This class broke
- Type above it: "# This class broke"\<esc>Go\<enter>
- Back to normal mode, make two blank lines at end of file# This file broke'
- Write at the end of the file: "# This file broke"
Reverse a file:
cat text.txt | vims '%g/.*/m0'
%g
- Work on all lines that match a pattern.*
- Matches all linesm0
- Move line to start of file
Sort the output of ls -l
by file size, using the
unix command sort
(which you can use inside vim):
ls -l | vims '1d' '%!sort -k5n'
1d
- Delete the first line ofls -l
%!
- Call the following external command on all linessort
- The unix sort command-k5n
- Sort by column 5, numerically
Find matching parentheses for a function call (something sed
and other regexp tools can't do),
and replace only those parentheses with square brackets:
> echo "0.9 * (sqrt(3.9 * (0.8 - 0.2)) / 20.0)" | vims -e 'sqrt(' '/sqrt(\<enter>f(lvh%hxhi[]\<esc>P' -t '%s/]()/]/g'
0.9 * (sqrt[3.9 * (0.8 - 0.2)] / 20.0)
-e 'sqrt('
- Only run this vim command on matching lines/sqrt(\<enter>
- In vim, hit/
to start a forward search, then search for "sqrt(" and go to the first matchf(
- From the first character of "sqrt", go to the open bracketlv
- Move right, so we are inside the "sqrt". Start visually selecting.h%
- Move back left to the open bracket, and use vim's%
command to move to the matching closing brackethx
- Move left, so we are inside the "sqrt" (but now on the far side). Delete the contents (which is saved to the clipboard!)hi
- Move left, so we are now at the open bracket again.[]
- Write out[]
which will be our new square brackets\<esc>
- Back to normal modeP
- Paste the contents into the[]
-t '%s/]()/]/g'
- This is a new command which simply cleans up the()
The heart of this script comes from a Google groups posting: posting, and then from an answer on SO
Thanks!
- Find way around vim command limit (only can seem to launch ~8 commands at once to vims - see issue #1)