What does the ${-#*i} mean in shell script? What does the ${-#*i} mean in shell script? linux linux

What does the ${-#*i} mean in shell script?


$- means shell flags.

${-#*i} means shell flags minus first match of *i.

If these two are not equal, then the shell is considered interactive (flag i is present).


See the top answer to What does “${-#*i}” != “$-” mean? on Unix & Linux by cuonglm:

$- is current option flags set by the shell itself, on invocation, or using the set builtin command:

$ echo $-himBH$ set -a$ echo $-ahimBH

"${-#*i}" is syntax for string removal: (from POSIX documentation)

${parameter#[word]}

Remove Smallest Prefix Pattern. The word shall be expanded to produce a pattern. The parameter expansion shall then result in parameter, with the smallest portion of the prefix matched by the pattern deleted.

If present, word shall not begin with an unquoted '#'.

${parameter##[word]}

Remove Largest Prefix Pattern. The word shall be expanded to produce a pattern. The parameter expansion shall then result in parameter, with the largest portion of the prefix matched by the pattern deleted.

So ${-#*i} remove the shortest string till the first i character:

enter code here$ echo "${-#*i}"mBH

In your case, if [ "${-#*i}" != "$-" ] checking if your shell is interactive or not.


tl;dr:

Conditional [ "${-#*i}" != "$-" ] evaluates to logical true if the current shell is interactive, in which case the exit code is set to 0, signaling true, which causes the enclosing if statement's then branch to be executed.

The conditional and the code in the question as a whole intentionally use only POSIX-compliant shell-language syntax and commands so as to be portable (work with all POSIX-compatible shells that may act as /bin/sh).

Note that if bash could be assumed as the shell, for instance, the same conditional could be more readably expressed as
[[ $- == *i* ]]


Explanation

  • ${-#*i} is a parameter expansion that removes the shortest prefix (#) that matches pattern *i from the value of named parameter $- (a named parameter is more commonly called a variable).

  • $- is a special parameter, which (link and emphasis added):

    expands to the current option flags (the single-letter option names concatenated into a string) as specified on invocation, by the set special built-in command, or implicitly by the shell.

  • An interactive shell implicitly adds option flag i to the value of $-; in other words: the presence of letter i in the value of $- implies that the shell at hand is interactive, and, conversely, the absence of i implies that the shell is noninteractive.

  • Thus, in parameter expansion ${-#*i}, pattern *i will only match inside the value of $- if an i is present, and, if so, by virtue of removing what *i matched, return a substring (suffix, in this case) of $-.
    In other words: only in an interactive shell does ${-#*i} not equal $-, because in a noninteractive shell - due to the absence of i - the parameter expansion has no effect, and the two operands are equal.


What the code in the question does as a whole:

In short: The code uses shell scripts it finds in /etc/profile.d to initialize the current shell; more specifically:

  • Scripts (files named *.sh) located in directory /etc/profile.d that are readable by the current user (-r) are passed to the . (dot) utility one by one, in alphabetical order. The dot utility executes the commands from each file in the current shell, typically to define aliases, functions, and environment variables. This is commonly known as sourcing a file.

  • Output produced by each sourced script is handled differently depending on whether the current shell is interactive or not:

    • interactive shell: output is passed through (will be visible in the interactive shell).

    • noninteractive shell: output is suppressed (>/dev/null 2>&1 is the POSIX-compliant way to silence both stdout and stderr).