1

Following some issues with scp (it did not like the presence of the bash bind command in my .bashrc file, apparently), I followed the advice of a clever guy on the Internet (I just cannot find that post right now) that put at the top of its .bashrc file this:

[[ ${-#*i} != ${-} ]] || return

in order to make sure that the bash initialization is NOT executed unless in interactive session.

Now, that works. However, I am not able to figure how it works. Could you enlighten me?

According to this answer, the $- is the current options set for the shell and I know that the ${} is the so-called "substring" syntax for expanding variables.

However, I do not understand the ${-#*i} part. And why $-#*i is not the same as ${-#*i}.

Community
  • 1
  • 1
user1284631
  • 4,446
  • 36
  • 61
  • 1
    Note that a much simpler equivalent would be `[[ $- = *i* ]]`. Instead of trying to remove a prefix ending in "i" and comparing to the original, you can just check if the original matches the pattern `*i*` (anything, followed by "i", followed by anything else). – chepner Jun 05 '13 at 13:05

2 Answers2

5
${parameter#word}
${parameter##word}

The word is expanded to produce a pattern just as in filename expansion. If the pattern matches the beginning of the expanded value of parameter, then the result of the expansion is the expanded value of parameter with the shortest matching pattern (the ‘#’ case) or the longest matching pattern (the ‘##’ case) deleted. If parameter is ‘@’ or ‘’, the pattern removal operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with ‘@’ or ‘’, the pattern removal operation is applied to each member of the array in turn, and the expansion is the resultant list.

Source: http://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html

So basically what happens in ${-#*i} is that *i is expanded, and if it matches the beginning of the value of $-, then the result of the whole expansion is $- with the shortest matching pattern between *i and $- deleted.

Example

VAR="baioasd";
echo ${VAR#*i};

outputs oasd.

In your case

If shell is interactive, $- will contain the letter 'i', so when you strip the variable $- of the pattern *i you will get a string that is different from the original $- ( [[ ${-#*i} != ${-} ]] yelds true). If shell is not interactive, $- does not contain the letter 'i' so the pattern *i does not match anything in $- and [[ ${-#*i} != $- ]] yelds false, and the return statement is executed.

blue
  • 2,683
  • 19
  • 29
  • 1
    Although you found the good reference, I think it is good to explain a little bit the particular case of the OP. – fedorqui Jun 05 '13 at 08:55
3

See this:

To determine within a startup script whether or not Bash is running interactively, test the value of the ‘-’ special parameter. It contains i when the shell is interactive

Your substitution removes the string up to, and including the i and tests if the substituted version is equal to the original string. They will be different if there is i in the ${-}.

perreal
  • 94,503
  • 21
  • 155
  • 181