I have trouble understanding how ${!path//:/$'\n'} works in the shell function below.

I have looked in man bash and considered the use of ${parameter/pattern/string} to subsitute : with \n, but in this case the expansion begins with ${!? Also, why is two forward slashes used in path// instead of a single?

pathprint () {
   if (($# == 0)); then
      set -- PATH
   for path; do
      echo "$path"
      echo "${!path//:/$'\n'}"

Finally, why doesn't the following "simplification" work?

pathprint () {
      echo "PATH"
      echo "${!PATH//:/$'\n'}"

In this case, $PATH is expanded before parameter expansion, and bash complains that no parameter exists with the name of the current value of $PATH?

  • 1
    The correct simplification would be echo "${PATH//:/$'\n'}", no exclamation mark (see choroba’s answer to understand why). Feb 15 at 15:31

for path; do doesn't specify the in, which means it iterates over the positional parameters. If you don't specify any when calling the function, $# will be zero and $1 will be set to the string PATH.

${!path} expands to the content of the variable whose name is in $path. It means, the parameter(s) to the function is not the path but the name of the variable(s) containing paths you want to print.

When using // instead of / in substitution, all occurrences of the pattern are replaced. Single slash only replaces the first occurrence.

  • I have never seen ! used in parameter expansion before? Is it a mixture of different parameter expansions (i.e the one that does substitution and one of the ${! ones? Where is ! documented?
    – Shuzheng
    Feb 15 at 17:57
  • @Shuzheng: Both ! and / are described in man bash under Parameter Expansion.
    – choroba
    Feb 15 at 18:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.