2

In my Oracle Linux box, I found a block of script in /etc/profile that is hard to figure out:

for i in /etc/profile.d/*.sh ; do
    if [ -r "$i" ]; then
        if [ "${-#*i}" != "$-" ]; then
            . "$i"
        else
            . "$i" >/dev/null 2>&1
        fi
    fi
done

My question is the variables in the if statement ${-#*i} and $-. What does that mean? And why should add an else statement to redirect output? Thanks!

KF Lin
  • 1,273
  • 2
  • 15
  • 18

4 Answers4

8

$- is a variable which stores the current options set by the shell.

${-#*i} is using substring removal to remove the shortest match to the pattern *i from the beginning of the variable. So if $- has the value abcifOO then ${-#*i} would be fOO. (You can read more about bash substrings here.)

This means that the test

[ "${-#*i}" != "$-" ]

will be true if the variable $- contains the option i, which means interactive mode is switched on.

All together this means that the output will only be redirected to /dev/null if you are in interactive mode.

Community
  • 1
  • 1
imp25
  • 2,327
  • 16
  • 23
4

It's checking whether the shell is interactive. The current shell's options are in $- and if removing anything followed by i yields a different result, it means that i was among the flags.

This would be a lot more readable and idiomatic, though:

case $- in *i* ) ... ;; esac

Also, it would be better to do the check once, outside the loop.

tripleee
  • 175,061
  • 34
  • 275
  • 318
2

What does $- mean?

From the manual:

-

(A hyphen.) Expands to the current option flags as specified upon invocation, by the set builtin command, or those set by the shell itself (such as the -i option).

When you're running bash interactively, then $- might exapnd to something like:

himBH

When you're executing a script, $- wouldn't have i (apart from some other flags above).

What does ${-#*i} mean?

Saying ${-#*i} causes the shortest match of *i from the beginning of the expansion of $- to be deleted. (Refer to Shell Parameter Expansion.)

In short, the inner if conditional in the example implies that while in the interactive mode the following is executed:

. "$i" >/dev/null 2>&1

and in the non-interactive mode, the following:

. "$i"
devnull
  • 118,548
  • 33
  • 236
  • 227
1

Just to add up a little more detail about $-. if you try to type in your terminal

[root@zee ~]# echo $-
himBH

Those appear to be shell 'set' values

Snippets from info bash --index-search=set

 '-h'

Locate and remember (hash) commands as they are looked up for execution. This option is enabled by default.

 '-m'

Job control is enabled (*note Job Control::).

 '-B'

The shell will perform brace expansion (*note Brace Expansion::). This option is on by default.

'-H'

Enable '!' style history substitution (*note History Interaction::). This option is on by default for interactive shells.

Using +' rather than-' causes these options to be turned off. The options can also be used upon invocation of the shell.

Zeeshan
  • 1,200
  • 12
  • 17