jeremysprofile
jeremysprofile

Reputation: 11445

Bash bad substitution with glob expansion for environment variables

How can I match environment variables which include the case-insensitive segment "proxy" that is not a prefix? I'm on bash:

root@PDPINTDEV9:~# echo ${SHELL}
/bin/bash

I want to unset a bunch of proxy variables simultaneously. They all have "proxy" or "PROXY" in the name, such as http_proxy or NO_PROXY. I would like to use glob expansion, which this answer & comment says is what bash uses.

Also based on that answer, I see that I can find environment vars which start with "PROXY":

root@PDPINTDEV9:~# echo "${!PROXY*}"
PROXY_IP PROXY_PORT

But that doesn't make sense with what I've read about glob expansion. Based on those, "${!PROXY*}" should match anything that doesn't start with proxy... I think.

Furthermore, I can't get anything that does make sense with glob syntax to actually work:

root@PDPINTDEV9:~# echo ${*proxy}
-bash: ${*proxy}: bad substitution
root@PDPINTDEV9:~# echo "${!*[pP][rR][oO][xX][yY]}"
-bash: ${!*[pP][rR][oO][xX][yY]}: bad substitution

SOLVED below: Turns out you can't. Crazy, but thanks everyone.

Upvotes: 1

Views: 623

Answers (2)

randomir
randomir

Reputation: 18697

Variable name expansion, as a special case of shell parameter expansion, does not support globbing. But it has two flavors:

${!PREFIX*}
${!PREFIX@}

In both, the * and @ characters are hard-coded.

The first form will expand to variable names prefixed with PREFIX and joined by the first character of the IFS (which is a space, by default):

$ printf "%s\n" "${!BASH*}"
BASH BASHOPTS BASHPID BASH_ALIASES BASH_ARGC BASH_ARGV BASH_CMDS BASH_COMMAND ...

The second form will expand to variable names (prefixed with PREFIX), but as separate words:

$ printf "%s\n" "${!BASH@}"
BASH
BASHOPTS
BASHPID
BASH_ALIASES
BASH_ARGC
...

Both of these forms are case-sensitive, so to get the variable names in a case-insensitive manner, you can use set, in combination with some cut and grep:

$ (set -o posix; set) | cut -d= -f1 | grep -i ^proxy
PROXY_IP
proxy_port

Upvotes: 2

John Bollinger
John Bollinger

Reputation: 180331

But that doesn't make sense with what I've read about glob expansion. Based on those, "${!PROXY*}" should match anything that doesn't start with proxy... I think.

No and no.

In the first place, the ! character is not significant to pathname expansion, except when it appears at the beginning of a character class in a pattern, in which case the sense of the class is inverted. For example, fo[!o] is a pattern that matches any three-character string whose first two characters are "fo" and whose third is not another 'o'. But there is no character class in your expression.

But more importantly, pathname expansion isn't relevant to your expression ${!PROXY*} at all. There is no globbing there. The '!' and '*' are fixed parts of the syntax for one of the forms of parameter expansion. That particular expansion produces, by definition, the names of all shell variables whose names start with "PROXY", separated by the first character of the value of the IFS variable. Where it appears outside of double quotes, it is equivalent to ${!PROXY@}, which is less susceptible to globbing-related confusion.

Furthermore, I can't get anything that does make sense with glob syntax to actually work: [...]

No, because, again, there is no globbing going on. You need exactly ${! followed by the name prefix of interest, followed by *} or @} to form the particular kind of parameter expansion you're asking about.

How can I match environment variables which include the case-insensitive segment "proxy"?

You need to explicitly express the case variations of interest to you. For example:

${!PROXY*} ${!proxy*} ${!Proxy*}

Upvotes: 1

Related Questions