Yes, history expansion is enabled by default only for interactive shells.
To enable it for a shell script, write:
To disable it in an interactive shell, write:
To determine whether or not history expansion is currently enabled, use some form of the following code:
case $- in (*H*) echo enabled ;; (*) echo disabled ;; esac
In starting to teach a shell class, I dug through the manual extensively to try to establish what an "interactive shell" really is. It's a whirlpool question, so let me save you some trouble:
The shell has MANY options. Some of these options are initialized in different ways when the shell has a controlling terminal (or when started with
-i, blah blah, whatever, see below).
ALL of the shell's options can be individually changed.
An "interactive shell" is a deceptive term when you try to define it precisely. It is really just a collection of option settings.
The question about which settings make a shell interactive or not is impossible to answer; it gets ridiculous. It is precisely the same philosophical question as the Ship of Theseus.
If you start an interactive shell, but then disable history expansion, use the
--noediting flag, set
--norc, turn off
expand_aliases, etc., etc., then in what sense is the shell interactive? Or, when does it become not interactive anymore? You can't answer these questions.
The truth is that "interactive" is just a convenient label for a collection of various shell options. Likewise "non-interactive." Same thing; just a collection of behaviors that can each one be changed individually.
Bottom line: the shell behaves differently when it is started "interactively" versus when it is started "non-interactively." Trying to precisely define these terms after start-up is silly. Just look at each individual option of the shell to understand its behavior.
I had forgotten that in addition to my own research, I posted about it extensively on this very site.