!
Execute a previous command from history
TLDR
Substitute with the previous command and run it with sudo
Substitute with a command based on its line number found with history
Substitute with a command that was used a specified number of lines back
Substitute with the most recent command that starts with a string
Substitute with the arguments of the latest command
Substitute with the last argument of the latest command
Substitute with the last command but without the last argument
Print last command that starts with a string without executing it
SYNOPSIS
The "!" character is used in various forms for history expansion:
Event Specifiers:
!! Re-execute the last command.
!string Re-execute the most recent command starting with 'string'.
!?string? Re-execute the most recent command containing 'string'.
!-n Re-execute the n-th command back from the current command.
!n Re-execute command number n from history.
Word Designators (used after an event specifier, e.g., !command:$):
:0 The command word (0th argument).
:n The n-th argument.
:$ The last argument.
:* All arguments (excluding the command word).
:^ The first argument.
Modifiers (used after event specifier and optional word designator, e.g., !command:s/old/new/):
:h Remove a trailing pathname component (head).
:t Remove all leading pathname components (tail).
:r Remove a filename suffix.
:e Remove all but the filename suffix.
:p Print the expanded command but do not execute it.
:s/old/new/ Substitute 'old' with 'new' in the event line.
:g Apply the subsequent modifier globally.
:& Repeat the previous substitution.
PARAMETERS
!!
Re-executes the last command.
!string
Re-executes the most recent command starting with 'string'.
!?string?
Re-executes the most recent command containing 'string'.
!-n
Re-executes the Nth command back in history.
!n
Re-executes command number N from history.
!cmd:0
Refers to the command word (0th argument) of the specified history event 'cmd'.
!cmd:n
Refers to the Nth argument of the specified history event 'cmd'.
!cmd:$
Refers to the last argument of the specified history event 'cmd'.
!cmd:*
Refers to all arguments of the specified history event 'cmd' (excluding the command itself).
!cmd:s/old/new/
Performs a substitution, replacing the first occurrence of 'old' with 'new' in the selected history event.
DESCRIPTION
The "!" character in Linux, primarily within interactive shells like Bash, is a powerful feature for history expansion. It allows users to quickly reference, modify, and re-execute commands from their shell's history list without retyping them. This significantly enhances productivity and reduces errors. When the shell encounters an unescaped '!' (unless it's part of an assignment or certain other contexts), it attempts to replace it with a command or argument from the history buffer. This expansion happens before the command is executed, effectively substituting the history reference with the actual command string. Common uses include re-running the last command, referencing specific arguments from previous commands, or searching history for commands containing a specific string.
CAVEATS
Shell Specific: The "!" history expansion is a feature of interactive shells (like Bash, Zsh, Tcsh) and not a standalone executable Linux command. Its behavior can vary slightly between shells.
Escaping: The "!" character needs to be escaped with a backslash (\!) or enclosed in single quotes ('!') if it is intended as a literal character, not for history expansion.
Security: When using history expansion, ensure you understand what command will be executed, especially with !string or !?string?, to avoid unintended actions or potential security risks if your history file contains sensitive or malicious commands.
Non-interactive use: History expansion is typically disabled in non-interactive shell scripts to prevent unexpected behavior. It can be toggled with set -H or set +H.
Ambiguity: Using ! as part of a variable assignment (e.g., VAR=!value) might not trigger history expansion depending on shell options (e.g., histverify).
DISABLING HISTORY EXPANSION
History expansion can be temporarily disabled for the current command by preceding the "!" with a backslash (\!, e.g., echo \!foo). To disable it for the entire session, you can use set +H (or set +o histexpand). To re-enable it, use set -H (or set -o histexpand).
LOGICAL NOT OPERATOR
While distinct from history expansion, "!" also serves as a logical NOT operator in shell conditional expressions. For instance, if ! grep -q "pattern" file; then ... means "if grep does NOT find the pattern...". This usage is common in shell scripting but does not involve history modification.
BANG PATHNAME EXPANSION (ZSH)
In Zsh, "!" can be used for pathname expansion, similar to globbing, to match filenames that do not match a pattern (e.g., rm *~ removes files not ending with ~). This is specific to Zsh and not part of Bash's history expansion.
HISTORY
History expansion, often referred to as "bang history", originated in the C shell (csh) developed by Bill Joy in the late 1970s. It was designed to address the common need to recall and modify previously executed commands. Given its immense utility, this feature was later adopted and significantly expanded upon in the TENEX C shell (tcsh) and subsequently integrated into the GNU Bourne-Again SHell (Bash) during its development in the late 1980s and early 1990s. Bash's implementation closely mirrors the C shell's syntax but includes additional modifiers and functionalities, making it a staple for interactive shell users.