Is it possible to do two different variable expansions in a single expansion?

Asked

Viewed 55 times

2

I have a variable, in array, $CLI_MODE. I fill it with a simple read:

read -a CLI_MODE

I would like to take the value of the first tiny element and, if possible, swap - for _. To get everything tiny I can use the expansion ,,:

$ variavel=aBcDe--FG

$ echo ${variavel,,}
abcde--fg

To replace the trace by the line below, I would do so:

$ variavel=aBcDe--FG

$ echo ${variavel//-/_}
aBcDe__FG

How do I get the equivalent result of these two expansions? As if it were ,, next to //-/_? It is possible to do this in a single expansion?

  • I believe two expansions aren’t possible, but maybe they’re nested, something like echo ${${variavel//-/_},,}. Have you tried something like this?

  • @Woss, I think an invalid construction, but it doesn’t hurt to try...

  • bash: ${${variavel//-/_},,}: bad substitution =(

  • In ZSH I managed to make a similar construction; echo ${${variavel//a/T}//-/_} resulted in TBcDe__FG, but the ,, also gave the bad substitution.

  • Yeah, but I’m stuck at Bourne Again... at least I can access the position [0] and do the downcase... as if the positional expansion did not interfere with other expansions

  • 1

    From what I’ve been doing, bash can’t seem to stand nested expansions. Then one way to do it on a single line would be to use one of the expansions and replace the second with some other command: echo ${variavel//-/_} | tr '[:upper:]' '[:lower:]' or echo ${variavel,,} | sed s/-/_/g

  • 1

    @hkotsubo Put life. As unpleasant as it is to me, it is still an answer. Anyway, invoking two expansions seems cheaper than making a pipeline and invoking an executable (echo usually is the built-in, hardly the executable /bin/echo, when at the level of shell script, so I’m not counting it)

  • 1

    Well, I put an answer (I was just looking for references in the documentation). Even if it is not the most pleasant solution, it is there as an option :-)

Show 3 more comments

1 answer

1


According to the bash documentation on expansions:

The basic form of Parameter Expansion is ${parameter}. The value of Parameter is substituted. The Parameter is a shell Parameter as described above (see Shell Parameters) or an array Reference (see Arrays).

That is, the parameter that is passed to the expansion must be a shell Parameter. And if we check the respective documentation, there is described that this parameter must be a variable, a positional parameter (as $1, $2, etc), or one of the special parameters (like the $@ and the $#, for example).

But when trying to make an expansion within the other (as for example ${${variavel//-/_},,}), the result of the first (the innermost) is any text, which is not a valid parameter, and so the external expansion fails.

Therefore, an alternative to doing everything in a single line would be to do just one of the expansions, and treat the other with some other command. In your case, it could be one of the options below:

echo ${variavel//-/_} | tr '[:upper:]' '[:lower:]'

echo ${variavel,,} | sed s/-/_/g

Other options for bash can be consulted here and here (I haven’t tested them all).

And another alternative, if possible, is to change shell. zsh, for example, supports nested expansions.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.