How to Properly Escape Exclamation Marks (!) in Bash Passwords and MySQL Commands


13 views

When dealing with passwords containing exclamation marks in Bash, you're actually encountering Bash's history expansion feature. The ! character triggers this behavior, which attempts to substitute commands from your history rather than treating it as a literal character.

# This fails because Bash tries to find command 'two' in history
$ mysql -umyuser -pone_@&!two

The standard escaping approach using backslashes often fails in this context because:

  1. Bash performs history expansion before parsing quotes and escapes
  2. The shell interprets the backslash differently in interactive vs non-interactive modes
# This still fails because history expansion occurs first
$ mysql -umyuser -pone_@&\\!two

Option 1: Single Quotes for the Entire Password

The most reliable method is wrapping the entire password in single quotes:

$ mysql -umyuser -p'one_@&!two'

Option 2: Disable History Expansion Temporarily

For scripts or aliases where quotes aren't feasible:

# In .bashrc or .bash_aliases
alias mysqllogin='set +H; mysql -umyuser -pone_@&!two; set -H'

Option 3: Use Double Quotes with Careful Escaping

When variables are involved:

PASSWORD="one_@&\!two"
mysql -umyuser -p"$PASSWORD"

The most robust solution for your .bashrc would be:

alias mysqlprod='mysql -umyuser --password="one_@&!two"'

For better security, consider using MySQL option files:

[client]
user = myuser
password = one_@&!two

Then connect simply with:

$ mysql --defaults-file=/path/to/my.cnf

When dealing with exclamation marks in passwords within Bash commands, you're encountering Bash's history expansion feature. The shell interprets ! as a special character that references previous commands unless properly escaped.

$ mysql -umyuser -pone_@&!two
-bash: !two: event not found

The standard backslash escape fails because Bash performs history expansion before processing escapes. This explains why your attempt with \! still resulted in an error:

$ mysql -umyuser -pone_@&\\!two
[1] 22242
-bash: !two: command not found

1. Single Quotes for the Entire Password

The most reliable method is wrapping the entire password in single quotes:

$ mysql -umyuser -p'one_@&!two'

2. Disabling History Expansion Temporarily

For scripts or aliases where quoting isn't practical:

$ set +H
$ mysql -umyuser -pone_@&!two
$ set -H  # Re-enable if needed

3. Double Escaping in .bashrc Aliases

For your specific .bashrc case:

alias mysqltest='mysql -umyuser -p"one_@&"'\\''!two'"'"

Using mysql_config_editor

A more secure approach than storing passwords in aliases:

$ mysql_config_editor set --login-path=mypath \
  --host=localhost --user=myuser --password
# Then enter the password (including !) at prompt
$ mysql --login-path=mypath

Environment Variables

Store the password in an environment variable:

export MYSQL_PWD='one_@&!two'
mysql -umyuser

While solving the escaping issue is important, consider that:

  • Password visibility in process listings can be a security risk
  • .bashrc entries may be visible to other users
  • MySQL's --defaults-file option provides better security

To verify your escaping works correctly without connecting to MySQL:

$ echo 'password_with_!mark'  # Test echo first
$ echo 'one_@&!two'           # Should output exactly as shown