Using bash history to get a previous command, copy it and then 'run' it but with the command commented - linux

Just a question to improve my bash skills. I always do this:
$ history | grep some_long_command
...
...
123 some_long_command1.........
124 some_long_command2.........
...
I can then run the command the command I found by doing:
!123
However, I often want to do this:
some_long_command1foobar
I.e. change the command before I run it. Can you use bash to run this command instead:
#some_long_command1
so it gets commented.
Then I don't have to use my mouse to highlight the command, edit it and then run it (I can just use the keyboard - faster).
I suppose I could write a script to do it but there might already be functionality built in somewhere....?

I'd suggest instead of using the history command, you use ctrl+r and start typing that command. When you press an arrow key as if to go to modify it, it will drop out of autocomplete recognition, and will let you edit before running.
UPDATE: also, if you want to cycle through the different commands that contain the string you just typed, keep on pressing ctrl+r

Actually, you can just append :p to the command to print it without actually running it. For example:
$ ls -la
$ !!:p
Will print out ls -la as the previous command without running it, and you can just press ↑ (up) to find it and edit it.
You can also do
!123:p
to print out the 123rd command as your previous command.

You can also try fc command to edit the command in the history.
WIKI says,
​fc​ is a standard program on Unix that lists or edits and reexecutes,
commands previously entered to an interactive shell. fc is a built-in
command in the bash shell; help fc will show usage information.
Apart from reverse-incremental search(Ctrl+R), we have some more bash shortcuts:
From man bash:
previous-history (C-p)
Fetch the previous command from the history list, moving back in the list.
next-history (C-n)
Fetch the next command from the history list, moving forward in the list.
beginning-of-history (M-&lt)
Move to the first line in the history.
end-of-history (M->)
Move to the end of the input history, i.e., the line currently being entered.
reverse-search-history (C-r)
Search backward starting at the current line and moving 'up' through the history as necessary. This is an incremental search.
forward-search-history (C-s)
Search forward starting at the current line and moving 'down' through the history as necessary. This is an incremental search.
non-incremental-reverse-search-history (M-p)
Search backward through the history starting at the current line using a non-incremental search for a string supplied by the user.
non-incremental-forward-search-history (M-n)
Search forward through the history using a non-incremental search for a string supplied by the user.
yank-nth-arg (M-C-y)
Insert the first argument to the previous command (usually the second word on the previous line) at point. With an argument n, insert the nth word from the previous command (the words in the previous command begin with word 0). A negative argument inserts the nth word from the end of the previous command. Once the argument n is computed, the argument is extracted as if the "!n" history expansion had been specified.
yank-last-arg (M-., M-_)
Insert the last argument to the previous command (the last word of the previous history entry). With an argument, behave exactly like yank-nth-arg. Successive calls to yank-last-arg move back through the history list, inserting the last argument of each line in turn. The history expansion facilities are used to extract the last argument, as if the "!$" history expansion had been specified.
shell-expand-line (M-C-e)
Expand the line as the shell does. This performs alias and history expansion as well as all of the shell word expansions. See HISTORY EXPANSION below for a description of history expansion.
history-expand-line (M-^)
Perform history expansion on the current line. See HISTORY EXPANSION below for a description of history expansion.
insert-last-argument (M-., M-_)
A synonym for yank-last-arg.
operate-and-get-next (C-o)
Accept the current line for execution and fetch the next line relative to the current line from the history for editing. Any argument is ignored.
edit-and-execute-command (C-xC-e)
Invoke an editor on the current command line, and execute the result as shell commands.

!123:gs/old/new/
Will run command 123 replacing the string 'old' with the string 'new'.

You can get to edit mode by hitting M-^ (option-shift-6 on a mac).
Type this:
!123M-^
And you'll be editing command #123. It's sort of like using ctrl-r, but starting with exclamation-point syntax.

Instead of using the history command, bind history-search-backward/history-search-forward to key shortcuts which can be remembered easily (I prefer PgUp/PgDown). To do that, put this into your .inputrc file:
"<key code>": history-search-backward
"<key code>": history-search-forward
To get <key code>, type Ctrl-V <key> in the shell, and replace the starting ^[ with \e in whatever was output.
After this is set up, you can just type some and press PgUp to get some_long_command. If you need some_long_command with_some_arg but there is a similar command some_long_command with_some_other_arg later in the history, you can cycle through until you reach it by typing some and then hitting PgUp repeatedly, or you can type some, hit PgUp, move the cursor to where the two commands start to differ, type a few characters and hit PgUp once more. This ability to quickly page through / differentiate between similar commands makes it in my opinion a much more comfortable tool than Ctrl-R.

You can also put
shopt -s histverify
in your .bash_profile, which causes any history expansion to appear on your command line without running it, allowing you to edit before doing so.

You may wan to try "suggest box"-like history https://github.com/dvorka/hstr - it reads Bash history and allows for quick navigation.
To get the last command simply type hh, navigate to the command and use right arrow to get it on command line (where you can edit it and/or add comment).

^p to get the last typed command in unix/solaris

Put
alias r='fc -s'
in your .bashrc (home dir)
then you can just type in
r <whatever>
at the command prompt and you will execute a copy of the last <whatever> command (same params) that is in your history. just hit up arrow to see what you have executed if you feel the need.

Related

Search current line in ZSH (vi mode)

How do I search/navigate within the current line in zsh? For example, if the cursor is at the end of the line..
// [] indicates cursor position
user#hostname: vim /etx/apache2/sites-enabled/defaul[t]
In vi normal mode, I'd like to use backward-search (?), type etx and have the cursor move like so:
// [] indicates cursor position
user#hostname: vim /[e]tx/apache2/sites-enabled/default
However, / and ? are mapped to history search, not inline search.
I know I can just type 9b and get there, but I find searching and moving to the match is easier than counting the number of words to jump.
Not sure if this was clear at all, let me know if I need to clarify things.
I hope I understood you right. You want to in zsh command line, move your cursor faster when you type commands.
e.g.
user#hostname: vim /etx/apache2/sites-enabled/defaul[t]
You want to move to the first e
I don't use vi-binding, but f and F are your friends.
In that example, you could 5Fe move backwards to the 5th e . If you don't want to count, you could Fe, then press ;, till it moves to the right position.
check vim help for detail:
:h f
:h F
Also faster way would be 0fe, for this example. Moving cursor to beginning, then to e
If I misunderstood your question, please leave comment, I would remove the answer.
This script adds this functionality to zsh:
https://github.com/soheilpro/zsh-vi-search
Maybe the ~/.inputrc file has mapped these keys to something strange? Or you're not fully understanding how the search history works.
Let's start fresh:
Remap these keys with bindkey:
bindkey -M vicmd "?" history-incremental-search-backward
bindkey -M vicmd "/" history-incremental-search-forward
Now, when you press 'esc' (for vi normal mode) and '?' you'll get a bck-i-search command:
%user#hostname: vim /etx/apache2/sites-enabled/defaul[t]
bck-i-search:
At this point, you type what you want to search for, e.g. 'etx'. And, the cursor moves to that position in this line. Note: if it doesn't find that pattern in this current line, it keeps on searching your history. This behavior is considered a feature!
You might notice that you can not repeatedly search (like pressing 'N' in vim). In this case add a few isearch bindings:
bindkey -M isearch '^N' history-incremental-search-backward
bindkey -M isearch '^R' history-incremental-search-forward
Now, pressing control-N repeats your search, while pressing control-S reverses the direction of the repeated search (note: the default order of this keybinding is reversed from forward to backward, since one is more often looking from end of the history back).
In short: treat the current line as the 'top' of your history. Using the vicmd '/' or '?' searches the entirety of that history. The '?' searches top down, while '/' searches from wherever the cursor is currently located in your history towards the 'top'. Another way of thinking about this is to imagine your history as one big file, and the current line your on is at bottom of that file. If that helps you grok it, you may feel that '?' is more pertinent than '/'.
Type v when you are in command mode of your shell, you will be taken to real ViM editor itself. Upon saving & exiting, it will automatically get executed.
I had the same issue. I didn't manage to solve it as such but found a suitable workaroud: added a binding for the edit-command-line function, which drops me to $EDITOR with current line in buffer. There it's easy to navigate to the given pattern.
See /usr/share/zsh/functions/Zle/edit-command-line on how to bind the function.

How to run a search and replace command without cursor moving in Vim?

In Vim, when I run a substitution command like
:%s/foo/bar/g
it replaces all occurrences of foo with bar in the entire buffer. When it completes, the cursor moves to the last location where foo was replaced with bar.
How can I run :%s/foo/bar/g without having the cursor leave its original location where it was before the substitution command was issued?
Is there some option I can set in the .vimrc file?
When the :substitute command is run, prior to any replacements being
carried out, the current position of the cursor is stored in the jump
list (see :help jumplist).
In order to return to the position before the latest jump, one can use
the `` or '' Normal-mode commands. The former
jumps exactly to the stored position; the latter jumps to the first
non-whitespace character on the line the stored position belongs to.
It is possible to both invoke a substitution command and move
the cursor back afterwards, at once, by issuing the command
:%s/pat/str/g|norm!``
or, if jumping to the containing line is sufficient, by using
the command
:%s/pat/str/g|''
It is not necessary to preface '' with norm! in the latter
command, because the '' address is allowed by the range syntax
of Ex commands and refers to the same line the Normal-mode
command '' jumps to (see :help :range); both just look into
the contents of the ' psudo-mark.
I just type Ctrl+O after the replace to get back to the previous location.
It's old, but for anyone coming across this question, I wanted to share my solution since it will work correctly even if nothing is substituted:
:exe 'norm m`' | %s/pattern/substitution/eg | norm g``
exe is needed since norm treats the bar as an argument.

Dynamic abbrev expand for the shell

Is there a function on one of the linux shells like the emacs dabbrev-expand?
First to give a definition:
M-xdescribe-functionEnterdabbrev-expandEnter
...
Expands to the most recent, preceding word for which this is a prefix.
Given that bash seems to be most heavily influenced by Emacs, looking there first reveals a few possibilities:
man bash(1), readline section
dynamic-complete-history (M-TAB)
Attempt completion on the text before point, comparing the text
against lines from the history list for possible completion matches.
dabbrev-expand
Attempt menu completion on the text before point, comparing the text
against lines from the history list for possible completion matches.
By default (or my system at least), M-/ is already bound to complete-filename:
$ bind -l | grep /
"\e/": complete-filename
You could re-bind it by putting
"\e/": dabbrev-expand
in your ~/.inputrc or /etc/inputrc.
Note that it only seems to complete the first word (the command), and only from history, not from the current command line as far as I can tell.
In zsh, I can't see anything in the man page that does this, but it should be possible to make it happen by figuring out the appropriate compctl command (Google mirror).

How to disable editing my history in bash

In bash, when I go back in history, edit some command and run it, this edited command is appended to history and the original one is left intact. But every once in a while I somehow manage to affect the original command, i.e. my edit replaces the original command back in history. I can't put my finger on how this happens.
Can someone explain? My goal is to avoid this, so any edit to a previous command always gets appended to history and never replaces the original.
I somehow manage to affect the original command, i.e. my edit replaces the original command back in history.
Right. If you go back in your history and edit the line without pressing return to execute the command but instead moving to another history entry, you've just edited the history entry. If you then list your history, you will see a * on the line indicating that you edited it. I find this "feature" immensely frustrating. Others have provided good examples of how to reproduce this.
My goal is to avoid this, so any edit to a previous command always gets appended to history and never replaces the original.
I too wanted to disable it. I found the solution via this answer over on unix.stackexchange.
To summarize, you need to enable the revert-all-at-newline readline setting which is off by default. If the setting is on then bash will revert any changes you made to your history when you execute the next command.
To enable this setting in your shell, you should add the following to your ~/.inputrc file and then restart your shell:
$include /etc/inputrc
set revert-all-at-newline on
The first line is needed because I guess that if you supply your own .inputrc file the default /etc/inputrc file is not included which is probably not what you want.
If you go back to some previous command and edit it, but then DON'T execute it (instead using history commands to go to some other command and execute it), then the edits will remain there in your history list.
Pressing Ctrl + C, after editing, counters this behaviour. It leaves the original command in tact i.e. it cancels remembering edits to the original.
Here's my own answer, please correct or provide more details if you can.
When the "vi" option is set in bash ("set -o vi" -- "Use a vi-style command line editing interface"), there are two modes of editing a command from history.
The first mode (let's call it "basic") is when you start editing immediately using Backspace, Del and character keys.
The other mode is the "vi mode", entered when you hit Esc.
If you want to keep your history intact, DO NOT use both modes in the same edit. I don't know how bash works exactly, but you can think of it this way:
Entering the "vi mode" applies any changes done in "basic mode" to the original command, and creates a copy of the command that you can edit further using vi-style commands.
The changes get applied when you hit Enter (execute), Up, Down or j,k (move to another command in history).
The changes do not get applied if you hit Ctrl-C.
Using either basic or vi-style editing ALONE does not affect the original command in history.
What do
echo $HISTCONTROL
echo $HISTIGNORE
give you?
Edit:
I was able to reproduce behavior similar to what you've seen by following these steps:
At the shell prompt, enter:
echo abcd
echo efgh
Press up arrow twice, so "echo abcd" is shown
Press 1 to add that character at the end
Press escape to enter command mode
Press left arrow twice so the cursor is on the "c"
Press x to delete the "c"
Press enter
Now as you step back through history, you'll see a new entry at the end:
echo abd1
and the entry that previously had "echo abcd" will now look like this:
echo abcd1
This is one way, I'm sure there are others.

How to repeat a command with substitution in Vim?

In Unix the ^ allows you to repeat a command with some text substituted for new text. For example:
csh% grep "stuff" file1 >> Results
grep "stuff" file1
csh% ^file1^file2^
grep "stuff" file2
csh%
Is there a Vim equivalent? There are a lot of times I find myself editing minor things on the command line over and over again.
Specifically for subsitutions: use & to repeat your last substitution on the current line from normal mode.
To repeat for all lines, type :%&
q: to enter the command-line window (:help cmdwin).
You can edit and reuse previously entered ex-style commands in this window.
Once you hit :, you can type a couple characters and up-arrow, and it will character-match what you typed. e.g. type :set and it will climb back through your "sets". This also works for search - just type / and up-arrow. And /abc up-arrow will feed you matching search strings counterchronologically.
There are 2 ways.
You simply hit the . key to perform an exact replay of the very last command (other than movement). For example, I type cw then hello to change a word to "hello". After moving my cursor to a different word, I hit . to do it again.
For more advanced commands like a replace, after you have performed the substition, simply hit the : key then the ↑ up arrow key, and it fills your command line with the same command.
To repeat the previous substition on all lines with all of the same flags you can use the mapping g&.
If you have made a substitution in either normal mode :s/A/B/g (the current line) or visual mode :'<,>'s/A/B/g (lines included in the current selection) and you want to repeat that last substitution, you can:
Move to another line (normal mode) and simply press &, or if you like, :-&-<CR> (looks like :&), to affect the current line without highlighting, or
Highlight a range (visual mode) and press :-&-<CR> (looks like :'<,'>&) to affect the range of lines in the selection.
With my limited knowledge of Vim, this solves several problems. For one, the last visual substitution :'<,'>s/A/B/g is available as the last command (:-<UP>) from both normal and visual mode, but always produces an error from normal mode. (It still refers to the last selection from visual mode - not to the empty selection at the cursor like I assumed - and my example substitution exhausts every match in one pass.) Meanwhile, the last normal mode substitution starts with :s, not :'<,'>s, so you would need to modify it to use in visual mode. Finally, & is available directly from normal mode and so it accepts repetitions and other alternatives to selections, like 2& for the next two lines, and as user ruohola said, g& for the entire file.
In both versions, pressing : then & works as if you had pressed : and then retyped s/A/B/, so the mode you were in last time is irrelevant and only the current cursor line or selection determines the line(s) to be affected. (Note that the trailing flags like g are cleared too, but come next in this syntax too, as in :&g/: '<,'>&g. This is a mixed blessing in my opinion, as you can/must re-specify flags here, and standalone & doesn't seem to take flags at all. I must be missing something.)
I welcome suggestions and corrections. Most of this comes from experimentation just now so I'm sure there's a lot more to it, but hopefully it helps anyway.
Take a look at this: http://vim.wikia.com/wiki/Using_command-line_history for explanation.

Resources