meaning of "command" prefix and suffix of "!" - vim

I am learning vim from vimtutor and I am currently on lesson 5 where they introduce external command prefix !command and external command suffix command!. I tested the command ls and did the following:
After typing :!ls, I got:
Desktop Downloads Music Public TEST
Documents Pictures Templates Videos
Press ENTER or type command to continue
When I saw the lists of folders and files, I knew that it acted like typing ls in the terminal, but when I typed :ls!, it got:
:ls!
1 %a "/tmp/tutorhN8t15" line 600
Press ENTER or type command to continue
Which made me confused of what the external command ! really means. What does it really mean?

:!command executes external command command.
:command! executes internal command command with a "bang" that usually modifies its behavior.
So…
:!ls executes your shell's ls command, which lists the files and directories in the working directory.
See :help :!.
:ls! executes Vim's ls command in a way that forces it to show listed and unlisted buffers.
See :help :ls.

Related

Search and replace in Vim across all the project files

I'm looking for the best way to do search-and-replace (with confirmation) across all project files in Vim. By "project files" I mean files in the current directory, some of which do not have to be open.
One way to do this could be to simply open all of the files in the current directory:
:args ./**
and then do the search and replace on all open files:
:argdo %s/Search/Replace/gce
However, when I do this, Vim's memory usage jumps from a couple dozen of MB to over 2 GB, which doesn't work for me.
I also have the EasyGrep plugin installed, but it almost never works—either it doesn't find all the occurrences, or it just hangs until I press CtrlC. So far my preferred way to accomplish this task it to ack-grep for the search term, using it's quickfix window open any file that contains the term and was not opened before, and finally :bufdo %s/Search/Replace/gce.
I'm looking either for a good, working plugin that can be used for this, or alternatively a command/sequence of commands that would be easier than the one I'm using now.
The other big option here is simply not to use vim:
sed -i 's/pattern/replacement/' <files>
or if you have some way of generating a list of files, perhaps something like this:
find . -name *.cpp | xargs sed -i 's/pattern/replacement/'
grep -rl 'pattern1' | xargs sed -i 's/pattern2/replacement/'
and so on!
EDIT: Use cfdo command instead of cdo to significantly reduce the amount of commands that will be run to accomplish this (because cdo runs commands on each element while cfdo runs commands on each file)
Thanks to the recently added cdo command, you can now do this in two simple commands using whatever grep tool you have installed. No extra plugins required!:
1. :grep <search term>
2. :cdo %s/<search term>/<replace term>/gc
3. (If you want to save the changes in all files) :cdo update
(cdo executes the given command to each term in the quickfix list, which your grep command populates.)
(Remove the c at the end of the 2nd command if you want to replace each search term without confirming each time)
I've decided to use ack and Perl to solve this problem in order to take advantage of the more powerful full Perl regular expressions rather than the GNU subset.
ack -l 'pattern' | xargs perl -pi -E 's/pattern/replacement/g'
Explanation
ack
ack is an awesome command line tool that is a mix of grep, find, and full Perl regular expressions (not just the GNU subset). Its written in pure Perl, its fast, it has syntax highlighting, works on Windows and its friendlier to programmers than the traditional command line tools. Install it on Ubuntu with sudo apt-get install ack-grep.
xargs
Xargs is an old unix command line tool. It reads items from standard input and executes the command specified followed by the items read for standard input. So basically the list of files generated by ack are being appended to the end of the perl -pi -E 's/pattern/replacemnt/g' command.
perl -pi
Perl is a programming language. The -p option causes Perl to create a loop around your program which iterates over filename arguments. The -i option causes Perl to edit the file in place. You can modify this to create backups. The -E option causes Perl to execute the one line of code specified as the program. In our case the program is just a Perl regex substitution. For more information on Perl command line options perldoc perlrun. For more information on Perl see http://www.perl.org/.
Greplace works well for me.
There's also a pathogen ready version on github.
maybe do this:
:noautocmd vim /Search/ **/*
:set hidden
:cfirst
qa
:%s//Replace/gce
:cnf
q
1000#a
:wa
Explanation:
:noautocmd vim /Search/ **/* ⇒ lookup (vim is an abbreviation for vimgrep) pattern in all files in all subdirectories of the cwd without triggering autocmds (:noautocmd), for speed's sake.
:set hidden ⇒ allow having modified buffers not displayed in a window (could be in your vimrc)
:cfirst ⇒ jump to first search result
qa ⇒ start recording a macro into register a
:%s//Replace/gce ⇒ replace all occurrences of the last search pattern (still /Search/ at that time) with Replace:
several times on a same line (g flag)
with user confirmation (c flag)
without error if no pattern found (e flag)
:cnf ⇒ jump to next file in the list created by the vim command
q ⇒ stop recording macro
1000#a ⇒ play macro stored in register a 1000 times
:wa ⇒ save all modified buffers
* EDIT * Vim 8 way:
Starting with Vim 8 there is a better way to do it, as :cfdo iterates on all files in the quickfix list:
:noautocmd vim /Search/ **/*
:set hidden
:cfdo %s//Replace/gce
:wa
Populate :args from a shell command
It's possible (on some operating systems1)) to supply the files for :args via a shell command.
For example, if you have ack2 installed,
:args `ack -l pattern`
will ask ack to return a list of files containing 'pattern' and put these on the argument list.
Or with plain ol' grep i guess it'd be:
:args `grep -lr pattern .`
You can then just use :argdo as described by the OP:
:argdo %s/pattern/replacement/gce
Populate :args from the quickfix list
Also check out nelstrom's answer to a related question describing a simple user defined command that populates the arglist from the current quickfix list. This works great with many commands and plugins whose output ends up in the quickfix list (:vimgrep, :Ack3, :Ggrep4).
The sequence to perform a project wide search could then be done with:
:vimgrep /pattern/ **/*
:Qargs
:argdo %s/findme/replacement/gc
where :Qargs is the call to the user defined command that populates the arglist from the quickfix list.
You'll also find links in the ensuing discussion to simple plugins that get this workflow down to 2 or 3 commands.
Links
:h {arglist} - vimdoc.sourceforge.net/htmldoc/editing.html#{arglist}
ack - betterthangrep.com/
ack.vim - github.com/mileszs/ack.vim
fugitive - github.com/tpope/vim-fugitive
One more option in 2016, far.vim plugin:
1. :grep <search term> (or whatever you use to populate the quickfix window)
2. :cfdo %s/<search term>/<replace term>/g | update
Step 1 populates the quickfix list with items you want. In this case, it's propagated with search terms you want to change via grep.
cfdo runs the command following on each file in the quickfix list. Type :help cfdo for details.
s/<search term>/<replace term>/g replaces each term. /g means replace every occurrence in the file.
| update saves the file after every replace.
I pieced this together based upon this answer and its comments, but felt it deserved its own answer since it's all in one place.
If you don't mind of introducing external dependency, I have brewed a plugin ctrlsf.vim (depends on ack or ag) to do the job.
It can format and display search result from ack/ag, and synchronize your changes in result buffer to actual files on disk.
Maybe following demo explains more
Make sure you’re using Neovim (or Vim 7.4.8+, but really just use Neovim)
Install FZF for the command line and as a vim plugin
Install Ag, so that it’s available automatically to FZF in vim
If using iTerm2 on OSX, set the alt/option key to Esc+
Usage
Search the text you want to change in the current directory and it’s children with
:Ag text
Keep typing to fuzzy filter items
Select items with alt-a
Deselect items with alt-d
Enter will populate the quickfix list
:cfdo %s/text/newText/g | :w
Now you have chabges made inside Vim NeoVim
source
You can do it with shell and vim's ex-mode. This has the added benefit of not needing to memorize other search-and-replace escape sequences.
Any command that can list files will work (rg -l, grep -rl, fd...). For example in bash:
for f in $(rg -l Search); do
vim -Nes "$f" <<EOF
%s/Search/Replace/g
wq
EOF
done
You can use any command, those prefixed with : in command mode, the same way you would inside vim, just drop the : at the start
I think that is because you have a huge amount of files been captured in memory. For my case, I do this by group files in different types, for example:
:args **/*.md
argdo <command>
:args **/*.haml
argdo <command>
Basically, I wanted the replace in a single command and more importantly within vim itself
Based on the answer by #Jefromi i've created a keyboard shortcut, which I had set in my .vimrc file like this
nmap <leader>r :!grep -r -l * \| xargs sed -i -e 's///g'
now from the vim, on a stroke of leader+r I get the command loaded in vim, which i edit like below,
:!grep -r -l <find> <file pattern> | xargs sed -i -e 's/<find>/<replace>/g'
Hence, I do the replace with a single command and more importantly within vim itself

what is the load order of scripts when you start up vim?

If you start up vim with something like this:
vim -S myscript.vim file.txt
What is the load order of scripts? Does myscript.vim get loaded after or before ~/.vimrc.
If you pass in vimscript commands to vim directly on the command line, when do they get executed relative to sourced and default vimscripts?
I believe vimrc is always first. You can run :scriptnames to get a list of sourced scripts in order in which they were first sourced in your Vim instance.
The help entry is way too long to post here, but it lists the order of everything that vim does at initialization. See :help initialization.
The answer is myscript.vim gets loaded dead last.
The vim -V option is a lifesaver here. (Capital -V, because -v starts in vi mode.) Just ran across it, after searching further since although the other answers answered your question, they don't show what wasn't sourced because it wasn't found. If I could send it back in time, I'd save myself a lot of time banging my head against strace output.
This will not only show you all of the scriptnames that it did source in order, but also all of the scriptnames that it would have sourced if they existed in order. So, you can discover what files you can create to load at the appropriate time.
$ vim -V
Adding it to your vim arguments easily answers the question.
$ vim -V -S myscript.vim file.txt
It shows myscript.vim as dead last.
It prints a ton, and winds up at a "Press ENTER or type command to continue" prompt, which lets you step through Autocommands.

Alternative to Up Arrow + Enter to run previous command?

Sometimes I have to run a command many times in succession, for example to see if a service has started, and it becomes tedious to move my hands away from my normal typing position to press the Up Arrow and Enter keys repeatedly. Is there a way to run the previous command without the Up Arrow and Enter keys, perhaps with an elaborate shell script?
I've tried the following, but it is unsatisfactory because it cannot execute aliases, and it is a little slow.
history | tail -2 | head -1 | cut -d' ' -f4- | cat > prev_command.txt
sleep .01
chmod 777 prev_command.txt
eval prev_command.txt
rm prev_command.txt
Ideally I'd have an alias to this script so I can type in something like "prev" in the command line and hit Enter to run the previous command again.
In bash, you can press ctrlp to go to the previous command -- that's a lot better than having to move to the arrow keys.
See also: https://github.com/fliptheweb/bash-shortcuts-cheat-sheet/
Use
!!
to run your previous command.
sudo !!
also works , for the record.
Instead of running the same command many times in succession, why not watch it instead? watch will run a specified command repeatedly and display the output in stdout so you can see it change over time.
watchcommand
I often use the "history expansion" feature in bash (usually activated with cntlR) -- it interactively searches through your history for the previous closest match.
See the bash manual section Searching for Commands in the History, and also Using History Interactively.
Are you an emacs or vi user? You can use
set -o vi
set -o emacs
to set emacs or vi keybindings. You can then use the emacs or vi key bindings in bash. I don't know if this should work for other shells. I believe the vi mode starts in insert mode, so you need to hit esc to enter command mode. In emacs mode (the default), you can use ctrl+p and then ctrl+j to move to the previous line and do a carriage return.
Otherwise, you can use !! as someone else suggested.
In bash:
$ help fc
fc: fc [-e ename] [-lnr] [first] [last] or fc -s [pat=rep] [command]
Display or execute commands from the history list.
fc is used to list or edit and re-execute commands from the history list.
FIRST and LAST can be numbers specifying the range, or FIRST can be a
string, which means the most recent command beginning with that
string.
Options:
-e ENAME select which editor to use. Default is FCEDIT, then EDITOR,
then vi
-l list lines instead of editing
-n omit line numbers when listing
-r reverse the order of the lines (newest listed first)
With the `fc -s [pat=rep ...] [command]' format, COMMAND is
re-executed after the substitution OLD=NEW is performed.
A useful alias to use with this is r='fc -s', so that typing `r cc'
runs the last command beginning with `cc' and typing `r' re-executes
the last command.
Exit Status:
Returns success or status of executed command; non-zero if an error occurs.
Note the suggestion for alias r; I use this frequently.
Depending on what terminal you're using, I know a lot used to have F3 as an option for repeating, but that's still outside the normal range for typing as well unless you have a special keyboard with more accessible function keys.
My keyboard makes the function keys easily accessible, but I don't do much command line work in unix any more, so I wouldn't be able to tell you for sure whether or not this is still possible.

Reuse last externally executed command in VIM

In VIM, I want to execute a command (like :!mkdir src/main/scala/xxx)
Then, I want to also make a subdirectory of the just created directory.
Can I have VIM retype the last used command and then I append the sub directory name to it
(So I can have :!mkdir scr/main/scala/xxx/yyy without retyping the whole stuff).
Can't you just hit : then the up arrow to go through your command history?
:!mkdir test
:!!/test2
will do what you want, see :h :!. Citation from there:
Any '!' in {cmd} is replaced with the previous external command (see also 'cpoptions').
// Why don't you use -p switch to mkdir? mkdir -p test/test2/test3/... will create directory with all its parents if they do not exist.

Bash Shell - What is equivalent of DOS shell F8?

When working an interactive bash session, one aspect from the Windows shell I miss is the F8 key where you start typing a command, hit F8 and the shell finds the most recent command entered in history that matches what you have typed so far. e.g.
me#Ubntu07:~>cd /home/jb<F8 Key Here>
brings up my prior command:
me#Ubntu07:~>cd /home/jboss/server/default/log
Is there any way to do this in bash ?
Hit Ctrl-R before you start typing.
(There may well be another version which finds commands based on what's already been typed - I wouldn't know, as Ctrl-R has always been good enough for me :)
Pressing Ctrl-R again shows the next match etc.
My Gentoo is configured in a way that I can press PgUp and PgDn to scroll through those commands in the command history that start with what’s currently in my command line.
# cd<PgUp>
results in:
# cd hydrogen
That’s pretty much the same function. It is defined in my /etc/inputrc with the following lines:
# mappings for "page up" and "page down" to step to the beginning/end
# of the history
"\e[5~": history-search-backward
"\e[6~": history-search-forward
I have these lines in my .inputrc file:
"\e[A": history-search-backward
"\e[B": history-search-forward
This binds history search to the up and down arrow keys. So you can start typing a command, kextload say, and then each tap of the up arrow will complete the line with the previous command that started with kextload.
All of my config files are public on github.
http://github.com/jonshea/config-files/tree/master
In your case !jb would print and then run that command.
e.g.,
$ nano logconfig.properties
$ !n
nano logconfig.properties
$
Of course if you want to be on the safe side, use ctrl-r first to bring up the interactive command history.
Ctrl + R does a history search. It's a bit different in that first you hit Ctrl + R and then type what you're looking for.
If you're just talking about a command, you can use the !<cmd> to do the last one. For example, say you entered python runscript.py a while ago; you can type:
!py
or something along those lines to run that command again.
To repeat an argument to a command, you could do something like this:
echo !py:1
which would echo runscript.py back to the terminal, in this example. The number after the colon refers to the argument you'd like to use from the given command.
There's a lot of other great information about the bash history here.
If you use vi input mode (set -o vi in bash or via set editing-mode vi in .inputrc), you can use normal vi commands to search the history (/). This gives you full regular expressions, too, which can be helpful for finding a complex command.

Resources