Using bash history to get a previous command, copy it and then 'run' it but with the command commented
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
History comment character
This is how I understand it:
There is the "normal" comment character, #
, which can't be changed. It indicates the start of a comment in scripts and in interactive sessions (unless the interactive_comments
shell option is disabled), and everything from that character on is ignored.
The history comment character can be set using histchars
; the default value is !^#
.
!
is used to indicate history expansion (like "repeat previous command":!!
)^
is to substitute something in the previous command:$ echo foo foo
foo foo
$ ^foo^bar^ # final ^ is optional
bar foo#
is the history comment character.
The history comment character is used:
In
~/.bash_history
, to mark timestamps as comments whenHISTTIMEFORMAT
is set:#1597532894
echo foo
#1597532908
histchars='!^@'
@1597532918
vim ~/.bash_historyNotice how the timestamp prefix switches to
@
after the second command.To skip history substitution for the remaining words on a line:
$ echo foo
foo
$ echo !$ @ !$ # !$
foo @ foo
$ histchars='!^@'
$ echo foo
foo
$ echo !$ @ !$ # !$
foo @ !$!$
is "the last word of the previous command". With the default settings (history comment character is#
),echo !$ @ !$ # !$
expands toecho foo @ foo # !$
and printsfoo @ foo
; everything after#
is ignored. When switching the history comment character to@
, the second!$
is not expanded tofoo
any longer.
When would you use that? I honestly don't know, and it really only applies to interactive shell sessions, where the default of #
make total sense, and anything else would be highly surprising behaviour to me. I can't find anything in the Bash release notes to explain what the intended purpose of being able to separately set the history comment character is.
How do I access the last command from a zsh function?
Using Gairfowl's answer with the associative array, I was able to formulate an appropriate solution:
function invim {
vim $(bash -c ${history[@][1]})
}
Here's how it works:
${history[@][1]}
is the text of the latest command, for example,find . -type f -name "*.txt"
- Run that command in a shell using
bash -c
- The resulting stdout is captured by the enclosing
$()
, and is then passed to vim as the filename(s) to edit. There are no enclosing quotes here to allow for multiple line outputs to all be opened.
Preserve bash history in multiple terminal windows
Add the following to your ~/.bashrc
:
# Avoid duplicates
HISTCONTROL=ignoredups:erasedups
# When the shell exits, append to the history file instead of overwriting it
shopt -s histappend
# After each command, append to the history file and reread it
PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a; history -c; history -r"
How to use arguments from previous command?
Just as M-.
(meta-dot or esc-dot or alt-dot) is the readline function yank-last-arg
, M-C-y
(meta-control-y or esc-ctrl-y or ctrl-alt-y) is the readline function yank-nth-arg
. Without specifying n
, it yanks the first argument of the previous command.
To specify an argument, press Escape and a number or hold Alt and press a number. You can do Alt--to begin specifying a negative number then release Alt and press the digit (this will count from the end of the list of arguments.
Example:
Enter the following command
$ echo a b c d e f g
a b c d e f g
Now at the next prompt, type echo
(with a following space), then
Press Alt-Ctrl-y and you'll now see:
$ echo a
without pressing Enter yet, do the following
Press Alt-3 Alt-Ctrl-y
Press Alt-- 2 Alt-Ctrl-y
Now you will see:
$ echo ace
By the way, you could have put the echo
on the line by selecting argument 0:
Press Alt-0 Alt-Ctrl-y
Edit:
To answer the question you added to your original:
You can press Alt-0 then repeatedly press Alt-. to step through the previous commands (arg 0). Similarly Alt-- then repeating Alt-. would allow you to step through the previous next-to-last arguments.
If there is no appropriate argument on a particular line in history, the bell will be rung.
If there is a particular combination you use frequently, you can define a macro so one keystroke will perform it. This example will recall the second argument from previous commands by pressing Alt-Shift-Y. You could choose any available keystroke you prefer instead of this one. You can press it repeatedly to step through previous ones.
To try it out, enter the macro at a Bash prompt:
bind '"\eY": "\e2\e."'
To make it persistent, add this line to your ~/.inputrc
file:
"\eY": "\e2\e."
Unfortunately, this doesn't seem to work for arg 0 or negative argument numbers.
How can I recall the argument of the previous bash command?
You can use $_
or !$
to recall the last argument of the previous command.
Also Alt + .
can be used to recall the last argument of any of the previous commands.
.bash_history does not update in Git for Windows (git bash)
I put this in my ~/.bash_profile
PROMPT_COMMAND='history -a'
Bash reg-exp substitution
Unfortunately, no, there's not really a better way. If you're just tired of making the keystrokes, you can use macros to trim them down. Add the following to your ~/.inputrc
:
"\C-x6": "\C-a#\C-m^"
"\C-x7": "\C-m\C-P\C-a\C-d\C-m"
Now, in a new bash instance (or after reloading .inputrc
in your current shell by pressing C-x C-r
), you can do the following:
- Type a bogus command (e.g.,
ls abcxyz
). - Press Ctrl-x, then 6. The macro inserts a
#
at the beginning of the line, executes the commented line, and types your first^
. - Type your correction (e.g.,
xyz^def
). - Press Ctrl-x, then 7. The macro completes your substitution, then goes up to the previous (commented) line, removes the comment character, and executes it again.
It's not exactly elegant, but I think it's the best you're going to get with readline.
PowerShell's Clear-History doesn't clear history
tl;dr
There are two histories to clear:
- PowerShell's own (
Clear-History
) - Additionally, in consoles (terminals), that of the
PSReadLine
module that is used for command-line editing by default in PowerShell v5+ ([Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()
)
- PowerShell's own (
In versions 1.2+ of
PSReadLine
(verify withGet-Module PSReadLine
) pressing Alt+F7 performs both calls for you, and therefore fully clears the in-session history.However, it does not clear the saved history that has accumulated up to this point, so even the cleared session's history will resurface in future sessions.
To also clear the saved history, you have to manually delete the file in which the saved session is stored (
(Get-PSReadlineOption).HistorySavePath
), as discussed below, and as wrapped by theClear-SavedHistory
function in the bottom section.
To complement CB.'s helpful answer and JVimes's helpful answer:
PowerShell's own history mechanism (
Get-History
,Clear-History
) is host-independent, which is why - somewhat unexpectedly - you also need to clear the hosts's command history separately.As for the console host's own history feature:
doskey
-style history feature, before modulePSReadline
shipped with PowerShell (see below):- There is no saved history - a history is kept only for the duration of the current session.
- Alt+F7 must be used to clear the console's history, with no (obvious) programmatic way to do it (in a
cmd.exe
console window you could usedoskey /reinstall
, but that doesn't work in PS). - CB.'s answer shows you how to simulate this keyboard combination; remember: this must be used in addition to
Clear-History
.
The
PSReadline
module comes with PowerShell v5 and v5.1 on Windows 10 and will also ship with Windows Server 2016, and also ships with the cross-platform Powershell (Core) v7+ edition; it replaces thedoskey
-style line-editing and command-history features with more sophisticated functionality; it is also possible to retrofit older Windows editions / PS versions (>= v3) versions with it, using the PowerShell Gallery (PSv3 and PSv4 must first install PowerShellGet).- Command history is now saved across sessions, in file
(Get-PSReadlineOption).HistorySavePath
. [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()
can be used to clear the current session's history (note that v1.2+ also supports Alt+F7 for interactive clearing of the current history).- CAVEAT: With
PSReadline
's default history-saving style,SaveIncrementally
, any sensitive commands have already been saved by the time to you call[Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()
, and will reappear in the next session. - The only way to handle this is to remove the saved-history file, as demonstrated in JVimes's answer which, however, invariably wipes out the entire history.
- IF you set up your profile to call
Set-PSReadlineOption -HistorySaveStyle SaveAtExit
every time a session starts - the setting apparenly does NOT "stick" by itself - you should be able to get away with only calling[Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()
(in addition toClear-History
) without also having to delete the saved-history file, in which case you won't lose your saved history from previous sessions. HOWEVER, AS OF v2.1.0 (the latest as of this writing),SaveAtExit
is BROKEN ALTOGETHER - no history is saved at all; see https://github.com/lzybkr/PSReadLine/issues/262
- CAVEAT: With
- Command history is now saved across sessions, in file
The following advanced function bundles all commands necessary to clear the command history (both for PowerShell itself and the console), both for doskey
-style and PSReadline
-module PowerShell console windows:
Note:
Because it's (currently) the only safe option,
PSReadline
's saved-history file is deleted as well, which means the entire history, including from previous sessions, is cleared.Therefore, a confirmation prompt is shown by default.
<#
# .SYNOPSIS
# Clears the command history, including the saved-to-file history, if applicable.
#>
function Clear-SavedHistory {
[CmdletBinding(ConfirmImpact='High', SupportsShouldProcess)]
param(
)
# Debugging: For testing you can simulate not having PSReadline loaded with
# Remove-Module PSReadline -Force
$havePSReadline = ($null -ne (Get-Module -EA SilentlyContinue PSReadline))
Write-Verbose "PSReadline present: $havePSReadline"
$target = if ($havePSReadline) { "entire command history, including from previous sessions" } else { "command history" }
if (-not $pscmdlet.ShouldProcess($target))
{
return
}
if ($havePSReadline) {
Clear-Host
# Remove PSReadline's saved-history file.
if (Test-Path (Get-PSReadlineOption).HistorySavePath) {
# Abort, if the file for some reason cannot be removed.
Remove-Item -EA Stop (Get-PSReadlineOption).HistorySavePath
# To be safe, we recreate the file (empty).
$null = New-Item -Type File -Path (Get-PSReadlineOption).HistorySavePath
}
# Clear PowerShell's own history
Clear-History
# Clear PSReadline's *session* history.
# General caveat (doesn't apply here, because we're removing the saved-history file):
# * By default (-HistorySaveStyle SaveIncrementally), if you use
# [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory(), any sensitive
# commands *have already been saved to the history*, so they'll *reappear in the next session*.
# * Placing `Set-PSReadlineOption -HistorySaveStyle SaveAtExit` in your profile
# SHOULD help that, but as of PSReadline v1.2, this option is BROKEN (saves nothing).
[Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()
} else { # Without PSReadline, we only have a *session* history.
Clear-Host
# Clear the doskey library's buffer, used pre-PSReadline.
# !! Unfortunately, this requires sending key combination Alt+F7.
# Thanks, https://stackoverflow.com/a/13257933/45375
$null = [system.reflection.assembly]::loadwithpartialname("System.Windows.Forms")
[System.Windows.Forms.SendKeys]::Sendwait('%{F7 2}')
# Clear PowerShell's own history
Clear-History
}
}
Related Topics
Linux Nasm Assembly Print All Numbers from Zero to 100
How to Format My Grep Output to Show Line Numbers at the End of the Line, and Also the Hit Count
How to Recompile Just a Single Kernel Module
Connecting to Amazon Aws Linux Server by Ssh on MAC
Shell Init Issue When Click Tab, What's Wrong with Getcwd
Building Linux Kernel on MAC Os X
What Is .D File After Building with Make
Git Aliases - Command Line Autocompletion of Branch Names
Startup Script with Systemd in Linux
Open Vim from Within a Bash Shell Script
Bash Variable Assignment Not Working Expected
How to Check If a Service That I Don't Know the Name of Is Running on Ubuntu
How to Include File in a Bash Shell Script
How to Copy Text from My Xterm Without a Mouse
Are Tar.Gz and Tgz the Same Thing
How to Add My Own Software to a Buildroot Linux Package