In a remote CentOS with Bash 5.0.17(1) where I am the only user via SSH I have executed read web_application_root
with:
$HOME/www
or with:
${HOME}/www
or with:
"${HOME}"/www
or with:
"${HOME}/www"
Aiming to get an output with an expanded (environment) variable such as MY_USER_HOME_DIRECTORY/www
.
While ls -la $HOME/www
works fine, ls -la $web_application_root
fails with all examples; an error example is:
ls: cannot access '$HOME/www': No such file or directory
I understand that read
treats all the above $HOME
variants as a string (due to the single quote marks in the error) and hence doesn't expand it.
How to expand variables inside read?
Best Answer
Variables are not expanded when passed to
read
. If you want to expand the$VAR
s or${VAR}
s whereVAR
denotes the name of an existing environment variable (limited to those whose name starts with an ASCII letter or underscore and followed by ASCII alnums or underscores) and leave all the other word expansions ($non_exported_shell_variable
,$1
,$#
,${HOME+x}
,$((1 + 1))
,$(cmd)
...) untouched, you could useenvsubst
(from GNUgettext
):You could make it a shell function that takes a variable name as argument and does both the reading and environment variable expansion with:
To be used for instance as:
To limit that substitution to a limited set of environment variables, you'd pass the list as a
$VAR1$VAR2...
literal argument toenvsubst
:(here tells
envsubst
to only substitute$HOME
,${HOME}
,$MYENVVAR
and${MYENVVAR}
in its input, leaving all other$VAR
s untouched).If you want to allow all forms of word expansions¹ (but note that then that makes it a command injection vulnerability), you could do:
Or again, as a function that takes the variable name as argument:
The same function with detailed inline documentation:
But your problems sounds more like an XY problem. Getting input via
read
is cumbersome and impractical. It's much better to get input via arguments, and then you can leave it to the caller's shell to do the expansions as they intend it.Instead of
(and remember that calling
read
withoutIFS=
and without-r
is almost never what you want).Make it:
And then the caller can do
your-script ~/dir
oryour-script "$HOME/dir"
oryour-script '$$$weird***/dir'
or evenyour-script $'/dir\nwith\nnewline\ncharacters'
as they see fit.¹ word expansion in this context refers to parameter expansion, arithmetic expansion and command substitution. That doesn't include filename generation (aka globbing or pathname expansion), tilde expansion nor brace expansion (itself not a standard
sh
feature). Using a here-document here makes sure'
and"
s are left untouched, but note that there still is backslash processing.