Exclamation Mark in Bash Script vs Terminal

bashshell-script

I have a simple bash script called foo.sh like this:

#!/bin/bash

echo "Foo!"

When I run it as ./foo.sh I get the Foo! message and everything's fine.
But if I echo "Foo!" directly from the console, then I obtain the expected behavior and message: bash: !": event not found.

I understand that the ! is presented as a previous command and if used inside p.e. single quotes, then it's considered as a literal.
I'm just wondering what is the difference here that running a script with that echo "Foo!" (even with source ./foo.sh works but directly from the console it doesn't.

Best Answer

By default, interactive bash shells have history expansion enabled (which is what controls the behaviour of !). Sourced files (which exist largely outside of the concept of history expansion) and scripts do not. From man bash (or the online manual):

set [--abefhkmnptuvxBCEHPT] [-o option-name] [arg ...]
-H: Enable ! style history substitution. This option is on by default when the shell is interactive.

This behaviour can be adjusted manually with set [+-]H, or set [+-]o histexpand, where -H/-o enables history expansion, and +H/+o disables it.

See also e.g.:

Related Question