Today we enter the semi-arcane world of your UNIX shell’s flags, the variables that determine how your shell will function for you. I’m focusing on the bash shell, as that’s the one I know best.

You can see your current flags by echoing the $- variable, as so:

$ echo $-
himBH

So what do those flags mean? You can type in man bash & search for SHELL BUILTIN COMMANDS & then, once you’ve found that section, scroll down (or search) for the set command. There you’ll find all the flags, written in that “kinda-informative-but-kinda-not” man page style we all know & love. Or you can check out “Table 8-13 bash features” on http://www.informit.com/articles/article.aspx?p=441605&seqNum=8, which does a nicer job explaining things.

Here’s what my flags mean (note that all of these are defaults):

  • h: Short for “hashall” (read that “hash all”), this tells bash to remember the locations of commands it has found through querying your PATH.
  • i: Short for “interactive”, which is good, because this is a shell with which I’m interacting (entering input & getting back output)!1
  • m: Short for “monitor”, this enables job control in bash (so you can send jobs to the background via bg, for instance).
  • B: Short for “braceexpand” (read as “brace expand”), this allows you to use the very efficient brace expansion in bash2.
  • H: Short for “histexpand” (read as “hist [history] expand”), this is what enables you to re-run a command from your history by prefacing its number with an exclamation point3.

There are several others (by “several” I mean “about 15 or so”), like:

  • e: Short for “errexit”, this causes bash to exit as soon as a command fails. Yikes!
  • C: Short for “noclobber”, this stops you from overwriting files via redirection.4

You can change these flags when you start the shell or after it’s started by using the set command. Let’s start with everything working like normal:

$ echo $-
himBH
$ history
<snip>  
500 ssh moe  
501 ssh larry  
502 ssh curly
$ !501
ssh larry

Because the H flag is set, I can re-run a command from history by using the exclamation point. Now I remove that flag (this is a bit confusing, but + removes the flag, while - turns it on) & notice what happens:

$ set +H
$ echo $-
himB
$ history
<snip>  
500 ssh moe  
501 ssh larry  
502 ssh curly
$ !501
-bash: !505: command not found

I can still view my history, but I can’t re-run any commands easily since I disabled histexpand. Bummer. Let’s turn that back on:

$ set -H
$ echo $-
himBH
$ history
<snip>  
500 ssh moe  
501 ssh larry  
502 ssh curly
$ !501
ssh larry

Now I can use the exclamation point again, & all is swell.

One final thing. Instead of echoing $-, you can quickly see your shell’s current options with a quick set command:

$ set -o
allexport   off
braceexpand on
emacs   on
errexit off
errtraceoff
functrace   off
hashall on
histexpand  on
history on
ignoreeof   off
interactive-commentson
keyword off
monitor on
noclobber   off
noexec  off
noglob  off
nolog   off
notify  off
nounset off
onecmd  off
physicaloff
pipefailoff
posix   off
privileged  off
verbose off
vi  off
xtrace  off

The only problem is that the flags aren’t listed here, so you have to do your own cross-indexing using the man page for bash, but it’s still a nice quick way to see what’s on & what’s off. You can also turn flags off & on using these options. So, for instance, to turn off history expansion (“histexpand” above), you’d use set +o histexpand, & to turn it on you’d use set -o histexpand. Same thing as set +H & set -H, respectively. As with many things UNIX, it’s your choice which syntax to use. You can go with brevity or comprehension—it’s up to you.

  1. OK, so how do you “see” a non-interactive shell? Sounds a bit like the observer effect, I know, but we can in fact easily create & view a non-interactive shell in action. Here’s how: create a text file named test.sh & enter into it the following:

    #!/bin/bash
    echo "I'm a shell & here are my flags:"
    echo $-
    

    Save the file, then make it executable:

    $ chmod 755 test.sh
    

    Run it:

    $ ./test.sh
    I'm a shell & here are my flags:
    hB
    

    See it? The only flags are h (“hashall”) & B (“braceexpand”)—no i for “interactive”. 

  2. “Braces” as in “curly braces” as in { & }. An example:

    $ ls
    $ mkdir {test1,test2}
    $ ls
    test1/ test2/
    $ mkdir test{3,4}
    $ ls
    test1/ test2/ test3/ test4/
    

    Pretty cool, eh? A great time-saver! 

  3. For example:

    $ history  
    <snip> 
    500 ssh moe  
    501 ssh larry  
    502 ssh curly  
    $ !501  
    ssh larry
    

    Use history to view the commands you’ve previously entered onto your shell, with each prior command numbered, then re-run a previous command by prefacing its number with an exclamation point. 

  4. By “redirection”, I’m referring to the > or >> command. So, for example:

    $ echo $-
    himBH
    $ echo "Hello" > test
    $ cat test
    Hello
    $ echo "Bonjour" > test
    $ cat test
    Bonjour
    

    Now let’s turn on the noclobber option & see what happens:

    $ set -C
    $ echo $-
    himBCH
    $ cat test
    Bonjour
    $ echo "Hello" > test
    -bash: test: cannot overwrite existing file
    

    Stopped in our tracks. Note that we could still delete the file, cp another file over test, or edit it manually. We just can’t redirect output to that file, a nice safeguard if you’re feeling really paranoid. Now let’s go back to normal & turn noclobber off:

    $ set +C
    $ echo $-
    himBH
    $ cat test
    Bonjour
    $ echo "Hello" > test
    $ cat test
    Hello