List variables with prefix where the prefix is stored in another variable
Solution 1
Bash doesn't parse nested variable expansions. You can do what you want with eval
: build the shell snippet ${!apple_@}
, then use it in a command that you execute with eval
.
prefix=apple_
eval 'vars=(${!'"$prefix"'@})'
Make sure that prefix
contains only valid identifier characters, otherwise the snippet could result in anything.
eval
is usually necessary to work with variables whose name is calculated dynamically, but in this specific case there's a completely different way to do the same thing: use the completion system. Bash's completion system works even from a script. The compgen
builtin lists one completion per line, which is ambiguous when completions can contain newlines, but this isn't the case here — they don't even contain wildcard characters, so the output can be split with a simple unquoted expansion. This will safely output nothing if the prefix contains characters that aren't valid in identifiers.
vars=($(compgen -v "$prefix"))
Solution 2
You could use env | grep '^prefix'
.
For example:
$ env | grep '^LESS'
LESSBINFMT=*u.
LESS=-MMqx4ij3
LESSOPEN=| /usr/bin/lesspipe %s
LESSCLOSE=/usr/bin/lesspipe %s %s
If you only want the values and not the variable names, use awk:
$ env | awk -F= '/^LESS/ {print $2}'
*u.
-MMqx4ij3
| /usr/bin/lesspipe %s
/usr/bin/lesspipe %s %s
(or print $1 for just the variable names)
Update 2019-05-17
I was brought back to this answer by an upvote, and realised there's an obvious improvement:
typeset -p
works better than env
, it outputs all variables whether they're exported or not. For example:
typeset -p | awk '$3 ~ /^apple_/ { print $3 }'
To use a variable rather than a fixed string:
prefix=apple_
typeset -p | awk '$3 ~ "^"pfx { print $3 }' pfx="$prefix"
or just export $prefix so it's available in awk's ENVIRON array:
export prefix=apple_
typeset -p | awk '$3 ~ "^"ENVIRON["prefix"] { print $3 }'
Note: with a little work, this can be made to work with other shells such as ksh or zsh, but it is important to note that the output format for typeset -p
is different in other shells, so the awk script will have to be modified to suit them.
Related videos on Youtube
Angelo
Updated on September 18, 2022Comments
-
Angelo over 1 year
I'm trying to list all the variables with a certain prefix, but that prefix is dynamically determined. For example:
prefix=apple_ apple_one=a1 apple_two=a2
If I simply do:
echo ${!apple_@}
I can get the variable names that start with apple_. However, I would like to do this by using the variable prefix somehow. Everything I've tried leads to a bad substitution. For example I cannot:
echo ${!${prefix}@}
-
Sparhawk over 8 yearsDepending on your exact problem, you might want to consider using arrays.
-
Sparhawk over 8 yearsI only mention it because I've tried to do the same thing. I refactored to use arrays, and even though I had to modify what I was doing conceptually, it made more "sense" in the end. And seemed less hacky.
-
Angelo over 8 yearsI had been trying to avoid associative arrays because I was burned a little while back due to portability issues. (I think they started support for that in Bash 4.)
-
philwalk over 5 yearsI have this same requirement, with the additional stipulation that I be able to export the variables, so bash arrays are excluded.
-
-
Gilles 'SO- stop being evil' over 8 yearsNot if the variables aren't exported. And this can break if there are environment variables containing line breaks.
-
Alessio over 8 yearstrue. nothing's perfect, and this is about as close as it's possible to get to what the OP wanted.
set
could also be used if you don't mind getting shell functions mixed in with your variables. -
mikeserv over 8 yearswell, it wont put the function names out if you tell it to behave:
set -o posix; set
-
Gilles 'SO- stop being evil' over 8 years@cas It's possible to get exactly what the OP wanted. It would be difficult if you wanted a POSIX solution, but
${!prefix}
is bash-specific in the first place (it isn't even a ksh feature). -
Alessio almost 5 years
typeset -p
works better thanenv
, outputs all variables whether they're exported or not. e.g.typeset -p | awk '$3 ~ /^BASH/ {print $3}'
, and avoids the potentially dangerous use ofeval
. I should have remembered typeset when I first posted this answer. to a variable rather than a fixed string:prefix="BASH"; typeset -p | awk '$3 ~ "^"prefix { print $3}' prefix="$prefix"