shopt are both shell builtins that control various options. I often forget which options are set by which command, and occasionally which option sets/unsets (
shopt -s/-u). Why are there two different commands that seemingly do the same thing (and have different arguments to do so)? Is there any easy way/mnemonic to remember which options go with which command?
As far as I know, the
set -o options are the ones that are inherited from other Bourne-style shells (mostly ksh), and the
shopt options are the ones that are specific to bash. There's no logic that I know of.
The difference is in the changed environment variable used by bash. Setting with the
set command results in
$SHELLOPTS. Setting with the
shopt command results in
shoptis not: Shell & Utilities: Detailed Toc | pubs.opengroup.org
Probably linked to the history mentioned by @Gilles.
Easy but lost in history. The
set command was originally used to modify the command line environment of the original unix shells
/bin/sh. Then as various Unix versions evolved, and new shell flavors was added, people realized that they needed to be able to change more (environment) things in order to keep shell scripting compatible. At that time Bash got very popular and the additional shell options was needed, introducing
You can actually see these compatibility attempts in the
$ shopt autocd off cdable_vars off cdspell off checkhash off checkjobs off checkwinsize off cmdhist on compat31 off compat32 off compat40 off compat41 off compat42 off complete_fullquote on direxpand off dirspell off dotglob off execfail off expand_aliases on extdebug off extglob off extquote on failglob off force_fignore on globstar off globasciiranges off gnu_errfmt off histappend on histreedit off histverify off hostcomplete on huponexit off interactive_comments on lastpipe off lithist off login_shell on mailwarn off no_empty_cmd_completion off nocaseglob on nocasematch off nullglob off progcomp on promptvars on restricted_shell off shift_verbose off sourcepath on xpg_echo off
But not in the
$ set -o allexport off braceexpand on emacs on errexit off errtrace off functrace off hashall on histexpand on history on igncr off ignoreeof off interactive-comments on keyword off monitor on noclobber off noexec off noglob off nolog off notify off nounset off onecmd off physical off pipefail off posix off privileged off verbose off vi off xtrace off
It looks like "set" options are inherited by subshells and shopts are not.
From the book "Linux Shell Scripting with Bash", p 63:
setcommand was used to turn options on and off. As the number of options grew,
setbecame more difficult to use because options are represented by single letter codes. As a result, Bash provides the
shopt(shell option) command to turn options on and off by name instead of a letter. You can set certain options only by letter. Others are available only under the
shoptcommand. This makes finding and setting a particular option a confusing task.
set originates from the bourne shell (sh) and is part of the POSIX standard,
shopt is however not and is bourne-again shell (bash) specific:
0 sjas@ssg 14:31:45 ~ set | grep -e SHELLOPTS -e BASHOPTS BASHOPTS=checkwinsize:cmdhist:complete_fullquote:dotglob:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:progcomp:promptvars:sourcepath SHELLOPTS=braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor 0 sjas@ssg 14:31:51 ~ shopt | column -t | grep -v off checkwinsize on cmdhist on complete_fullquote on dotglob on expand_aliases on extglob on extquote on force_fignore on histappend on interactive_comments on progcomp on promptvars on sourcepath on 0 sjas@ssg 14:31:57 ~ set -o | column -t | grep -v off braceexpand on emacs on hashall on histexpand on history on interactive-comments on monitor on 0 sjas@ssg 14:37:41 ~ sh $ set -o Current option settings errexit off noglob off ignoreeof off interactive on monitor on noexec off stdin on xtrace off verbose off vi off emacs off noclobber off allexport off notify off nounset off priv off nolog off debug off $ shopt sh: 3: shopt: not found $