How to make the specified command run in vim? - shell

I know how to make shell command run in vim,in command mode,type
:!shell_command
Now, I have a command in line 16 of a file open in Vim.
cp /home/debian/Downloads/rar/rar /usr/local/bin
How can I run this command in vim, without typing all of it?
When I hit :! to open up the ex command line and then use <C-r>", I get this:
ls /tmp^m
I have to erase ^m with the backspace key, and press the enter key, is that right?
can i not to let ^M to be shown ?

To run the command on the line your cursor is on you can yank the line into you clipboard. Type :! to open up the ex command line and then use <C-r>" to paste the command onto the command line.
So with the cursor on the line type and hit enter.
yy:!<C-r>"
Take a look at :h <c-r>.
CTRL-R {0-9a-z"%#:-=.} *c_CTRL-R* *c_<C-R>*
Insert the contents of a numbered or named register. Between
typing CTRL-R and the second character '"' will be displayed
to indicate that you are expected to enter the name of a
register.
The text is inserted as if you typed it, but mappings and
abbreviations are not used. Command-line completion through
'wildchar' is not triggered though. And characters that end
the command line are inserted literally (<Esc>, <CR>, <NL>,
<C-C>). A <BS> or CTRL-W could still end the command line
though, and remaining characters will then be interpreted in
another mode, which might not be what you intended.
Special registers

Simple answer:
:exec '!'.getline('.')

Related

Shortcut to jump to the previous white space in a bash command line

To jump to the previous word in a command line, I use Alt + b.
However, the names of my files are pretty long and look like this:
2018_09_03_abcdef_ghijkl_mnopqr_stuvwx_yz.txt
When I want to change the name of these files, I use the command mv and a shortcut** that permits me to paste the first word/argument (the current name of the file). This gives me the following command:
$ mv 2018_09_03_abcdef_ghijkl_mnopqr_stuvwx_yz.txt 2018_09_03_abcdef_ghijkl_mnopqr_stuvwx_yz.txt
Then I either want to change the date of the day and/or the first letters of the file name to get for example the final command line:
$ mv 2018_09_03_abcdef_ghijkl_mnopqr_stuvwx_yz.txt 2018_09_04_ABcd1234_ghijkl_mnopqr_stuvwx_yz.txt
To make the change at the beginning of the file name, I have to type the shortcut Alt + b several times since this shortcut considers every letters separated by an underscore as a word.
I would like to be able to jump directly to the beginning of the name (not the beginning of the line) to modify it. A shortcut targeting the white space would be ideal.
I have not been able to find such a shortcut that would skip the underscores and go directly to the previous white space.
Did anyone already create a shortcut in bash that allows you to do this?
Would the only possible way to accomplish this be to switch from emacs mode to vi mode (set -o vi) and use the vi shortcut:
F + space
?
Thank you very much in advance!
** The shortcut I found to paste the previous word in the current command line and paste it in the same current command line uses Alt + j and has to be added in the '~/.inputrc' file (followed by bind -f ~/.inputrc):
"\ej":"!#:$\e^"
There are several shortcuts to navigate bash command line. Here's another list.
Assuming cursor is at the end of the line, it could jump to 03 (day part) by typing Meta+7 Meta+b (2 keystrokes without releasing Meta key).
Now, for the file name changes, brace expansion could be used to get a command like this that provides the second argument from expansion.
mv 2018_09_{03_abc,04_ABC}def_ghijkl_mnopqr_stuvwx_yz.txt

Pipe a vim command after a shell command

I'm trying to make a key mapping in vim that (a) saves current file (b) performs a git action, using shell (c) quits current vim editor.
I've tried the following methods but still can't figure it out.
Method 1 - in Vim command line
:w | !git commit -am "auto" | q
Method 2 - in .vimrc
map :W :w \| !git commit -am "auto"
map :L :Wq
Problem
The problem is that the pipe | can only be used to append shell commands. How do I do 'a Vim command' + 'a shell command' + 'a Vim command'? How to pipe a vim command after a shell command?
You need to execute those three commands separately. This is what <CR> is for:
nnoremap <key> :w<CR>:!git commit -am "auto"<CR>:qa<CR>
Have you tried vim-fugitive?
You can git commit -am using that plugin and then add your git command.
So you would write something like:
Gcommit -am "auto"
I tested it briefly. I've put this into my .vimrc:
function! CommitAndQuit()
execute "Gcommit -am 'auto'"
execute "q"
endfunction
Then type :call CommitAndQuit() and it will do what you want.
This feels related as I ended up here!
So if you want to bind this in a command you won't be able to use <cr> and pipe also won't work.
In that case the right thing to do is use a function and just call the function from that command.
In this example I had a shell script to grep some log files for errors and output the result into .errors, which then gets opened in the quickfix. The redraw is because silent messes your screen up with external commands!
function! ReadErrors()
silent !read-errors
redraw!
cfile .errors
endfunction
command! ReadErrors call ReadErrors()
There are 3 scenarios I see here:
Adding a vim command
If you want to add a new vim command, so that typing :W would write the buffer, do git commit and quit vim, you'll need to follow JonnyRaa's answer. Namely, define a function, and then define a command that executes that function:
function! WriteCommitAndQuit()
w
silent !git commit -am "auto"
q
endfunction
command! W call WriteCommitAndQuit()
Notes:
These lines can be put into ~/.vimrc, or executed directly after hitting : to go into command line mode.
I used silent to avoid getting the "Press ENTER or type command to continue" prompt.
You might want to use write and quit instead of w and q, for nicer-looking code. (Conversely, silent can be shortened to sil if you're in a hurry...)
Adding a keyboard mapping
If you want to just be able to hit a single key to run these commands, you'll need to add a mapping, and the trick for putting a shell command in the middle is to use <CR> to simulate hitting ENTER:
map <F10> :w<CR>:silent !git commit -am "auto"<CR>:q<CR>
Notes:
Once again, this can go in ~/.vimrc or execute by hitting : and typing it directly.
Instead of silent, you can just add an extra <CR> after the shell command.
Executing directly
Sometimes there's a sequence of commands you want to run repeatedly, but they're not worth bothering to persist into vimrc, since they are ad-hoc and won't be useful in the future. In this case, I just execute the line and then rely on the up arrow to bring the line again from history and execute it.
In this case, the trick is to add an escaped LF character in the middle of the command, using Ctrl-V, Ctrl-J:
:w | silent !git commit -am "auto" ^# q
Notes:
The ^# in the command is what gets shown when I hit Ctrl-V, Ctrl-J. It won't work if you hit Shift-6, Shift-2. However, it does seem to work if I hit Ctrl-Shift-2.
You can also replace the first pipe character with LF, but you don't have to.
In case you're curious, Ctrl-J is LF because LF is ASCII 10, and J is the 10th letter of the ABC. Similarly, Ctrl-I is Tab, Ctrl-M is CR, and Ctrl-] is Escape, since Escape is ASCII 27, and if you look at an ASCII table, you'll realize that ] is the 27th letter of the ABC.
i use this command to copy current file path to system clipboard.
map <silent> <leader>vv :echo expand('%:p') \| !syscopy.sh <cr>
simple why for me is:
Work
:echo expand('ls') | echomsg 'test'
Not work
:!ls | echomsg 'test'
You can't:
A '|' in {cmd} is passed to the shell, you cannot use it to append a Vim command. See |:bar|.

Jump to string in current line while using Bash in VI mode

While navigating in BASH using VI mode, I can jump back to a specific character (e.g. '-') of the current command line via the following command:
F-
How can I jump back to a specific string (e.g. '--path') in the current command line of BASH? I know navigating in VI but I did not understand how to perform regex search in current command line of BASH.
According to here, what you want doesn't seem possible. The ?word and /word bindings search in command history rather than in the current command line.
But in vi mode, you can press ESC v to open the current command line in an editor. Then you can edit & save the command and it will be executed (source).
Of course, as pointed out in nur-sh's answer, you can simply keep pressing B to get to the word.
You could use the find command which searches backwards from where you are
?word
or you could keep pressing B to get to the word
(this command goes back one Word at a time).

Disable delete key in terminal prompt

I modified my prompt in my .bashrc file using the following command:
PS1='\[$(tput bold)\e[1;34m\w\e[m$ '
Now my prompt shows the current directory in bold blue color followed by the $ sign. On a new prompt, if no other text has been entered, I press the delete key nothing happens.
However, if I enter any text, say cd, delete that and then press the delete key once more, it will delete my prompt. How can I change my .bashrc file so my prompt can never be deleted?
Bash is confused about how long your prompt actually is. You can tell bash by enclosing non-printable parts of the prompt with backslash-brackets: \[....\].
Your prompt, however only contains the opening bracket, making bash believe that the prompt is very short, so it happily removes almost all of it in some situations. A proper use of the bracketing would look like this:
PS1='\[$(tput bold)\e[1;34m\]\w\[\e[m\]$ '
That is, everything is in backslash-bracket except the working directory and the dollar sign, because those are the only parts that actually consume space on the terminal screen.

In bash, how does one clear the current input?

Suppose in bash you start writing a command like:
$ rm -rf /foo/bar/really/long/path/here
and then realize you don't want to execute this after all. Is there a way to clear the input with one or two keystrokes?
What I have been doing lately is prepending echo and enclosing the input in quotes (Ctrl+A, echo ", Ctrl+E, ") then hitting enter. Is there a faster way?
Press Ctrl-U to delete everything before the cursor. The deleted command will be stored into a buffer. Press Ctrl-Y to paste the deleted command.
(Optional: Press End or Ctrl-E to jump to the end of the input first.)
Alternatively, press Ctrl-C to abort what you're typing.
Try Ctrl+U. That clears the input line.
Found a short reference at http://www.ice2o.com/bash_quick_ref.html while searching.
ctrl + e (if not at the end of the line) plus ctrl + u will do it.
Ctrl-U, Ctrl-K does the trick as well.
Ctrl-U deletes everything from the beginning of the line up to the cursor, Ctrl-K deletes everything from the cursor to the end of the line. (It is sometimes useful to use only one of them.)
There are two options to do this
ctrl+c - this clears the whole line, no matter where the cursor is.
ctrl+u - this clear the line from the position of the cursor until the beginning.
A nice shortcut is pressing Esc#. It will prepend a # character (thus making the line a comment) and then press enter. If you then decide that you still the need the command, you still have it in your history :)
Pressing Esc plus Backspace in bash will clear everything up to the cursor's position.
(In Cygwin, this will clear the input up to the next word. Words are separated by spaces, underscores, ...)
This is an expansion of knittl's answer that stores the line in the console history by prefixing with a hash. Overcoming drawbacks of the clipboard, such as accidental overwriting or being unable to view the cut line for reference.
Comment Line & Return New Prompt
Use either key shortcut:
Esc,#
Alt+#
A hash character # will be prepended to the line, thus turning the whole line into a comment. It will also return a new prompt, as if enter was pressed by the user. e.g.
$ #rm -rf /foo/bar/really/long/path/here
$
Retrieve Commented Line
To recover the old line from console history use one of the following shortcuts:
Up
Ctrl+p
Repeat key shortcut until the desired line appears.
Quick Hash Prefix Removal
To remove the line's hash # prefix there are a few different options available:
Remove first character and immediately execute command:
Esc,1,Esc,#
Alt+-, Alt+#
Move cursor to start and remove first character, without executing the command:
Home, Delete
Ctrl+a, Ctrl+d
Consider that using Ctrl-U (or Ctrl-E and then Ctrl-U) will store what you clear in a buffer so that you can then paste it later using Ctrl-Y.
If you are using Bash in vi mode (set it with set -o vi), then press Esc to switch to the normal mode of vi, and type dd to delete the current line!
To delete the current line, try:
Ctrl-X, Ctrl-U
As an alternative you may use:
Esc-D
which requires in ~/.inputrc:
"\ed": kill-whole-line
see: http://codesnippets.joyent.com/posts/show/1690

Resources