1

I'm currently working on cleaning up some shell scripts. While doing that, I came across something that looks like this:

if [ ${#VARA} -eq 0 ] || [ ${#$VARB} -eq 0 ] || [ ${$VARC} -eq 0 ]; then
  ...
fi

As you can see, there are three different types of things going on here with variables: ${#V}, ${#$V}, and ${$V}. I would love an explanation of each of these please. (Plus Shellcheck is complaining about the last one.)

Matthew Herbst
  • 29,477
  • 23
  • 85
  • 128
  • 1
    My bash complains already about the 2nd one. Which shell is it? Any chance the original author did not know what he was doing and just tried all three. The first is the string length of VARAs value. – Harald Mar 25 '16 at 06:55
  • @Harald there is a very good chance of that. And yes, it is Bash. The line in question is in a very large script. I can't promise that it is even being used, but I just thought it was interesting since I had never seen the syntax before. – Matthew Herbst Mar 25 '16 at 06:59
  • No wonder you did not see it, if it does not work (except the 1st):-) Or maybe it worked in ancient versions of bash. – Harald Mar 25 '16 at 07:04

1 Answers1

1

This syntax is part of POSIX (thence Bash) shell parameter expansion. It counts number of characters for a variable :

$ myvar="foo" && echo ${#myvar}
3

The last two ones ${#$VARB} and ${$VARC} have not a valid syntax. You cannot declare a variable this way.

Quite similar to your ${$VARC} is the valid \$$myvar, used for indirect reference with eval or echo. This syntax refers to the literal string "$foo" (when myvar="foo"). As @chepner mentionned, because of eval, it's not recommended to use it. The Bash 2.0 introduced the ${!myvar} syntax for indirect variable reference that is a much preferable alternative.

Note : you should avoid uppercase for variable names not to confuse with shell variables which are also uppercased by convention.

Community
  • 1
  • 1
SLePort
  • 15,211
  • 3
  • 34
  • 44
  • 1
    `${#myvar}` is not just `bash`, but part of the POSIX shell specification. – chepner Mar 25 '16 at 12:47
  • 1
    `othervar=\$$VARC` sets `othervar` to the literal string `$foo` (if `foo` is the expansion of `$VARC`). – chepner Mar 25 '16 at 12:48
  • Thanks @chepner. Updated my approximative formulation. – SLePort Mar 25 '16 at 13:22
  • That's not an indirect variable reference, though; as usual, the "advanced" bash scripting guide gets it wrong. You need to further pass `$foo` through `eval` to get the value, which is not recommended. That's why `bash` introduced *actual* indirection with `${!foo}`, which expands to the value of the parameter whose name `$foo` expands to. – chepner Mar 25 '16 at 13:45
  • Added the omitted `eval` mention. – SLePort Mar 25 '16 at 14:28