0

I wrote a simple script.

read -p "Enter the path: " path
echo "$path"

I give the input as

$HOME

And the output is:

$HOME

And if I write

echo "$HOME"

outputs

/home/sam

so why not in the former case?

  • 4
    Basically for the same reason why the C code char *str = "foo()"; printf("%s\n", str); doesn't call the function foo(). What is read with read, and what you print with echo is just data, not shell code. The shell isn't a macro processor that goes back to look at the expanded text to parse it again for further expansions. And it's very well that it isn't, since otherwise people could cause all kinds of havoc with e.g. filenames containing stuff that looks like shell syntax or expansions. – ilkkachu Jan 08 '22 at 14:13
  • @ilkkachu then why does echo "$HOME" gives an output /home/sam. – klaus_03 Jan 08 '22 at 14:17
  • 2
    Because now the command line, the command that actually gets parsed and interpreted for shell syntax does contain the expansion $HOME. Same as how echo "$path" expands $path. Similar to how printf("%s\n", foo()); does call the function. It's the difference between code and data. – ilkkachu Jan 08 '22 at 14:20
  • The shell evaluates variables in double quotes but not in single quotes. The read function is neither. It simply sets input into a variable. Just as a mental exercise, imagine how dangerous it would be if read always evaluated the variables. – jsbillings Jan 08 '22 at 14:25
  • OTOH, note that read without the -r option does do some mangling of the input data, namely takes backslashes as escapes for field splitting. (which you'd hardly ever want...) But it doesn't evaluate all shell syntax, or even only variable expansions (or quotes, or...) – ilkkachu Jan 08 '22 at 14:31
  • 1
    For the "how" rather than the "why" see How to expand variables inside read? – steeldriver Jan 08 '22 at 15:29
  • @klaus_03 although a lot has been covered by these comments, are you looking something like eval printf '%s\n' "$path" ? The use of eval is often associated with security risks, so have a look here before using it: https://mywiki.wooledge.org/BashFAQ/048?highlight=%28eval%29 – Valentin Bajrami Jan 08 '22 at 22:22
  • Got it, thanks! – klaus_03 Jan 09 '22 at 09:28

1 Answers1

0

path becomes the string $PATH, not the "interpretation" of it. That interpretation only happens in specific contexts – for example, if you type it "bare" on an interactive shell command prompt; but definitely not in read (otherwise you couldn't use read to read text files containing $, for example!).

Remember, expansion is a functionality that you never want to have enabled everywhere – it would make it hard to write programs that pass around variables as variables, instead of their content. Thus, programming language designers (or in the case of shells, decades of more or less organic development) decide where that expansion happens, and where not. There's not really a "why" here: it's how it's defined.

You can eval value="$path" if you wish, then you get that. I do not recommend that, as it basically makes your entry a shell prompt and if the user enters, for example, $(rm -rf /), that would allow them to delete everything...

All in all, I think this is more of a software design problem: what kind of things do you want to allow the user to do?

In this case, $HOME might pretty much be the only "special" case you'd want to allow. I'd recommend replacing that with ~, as it's the canonical short form, and do something like:

read "Enter foo bar baz:" raw_path
if [[ ( ! -d "${raw_path}" ) && "${raw_path:0:1}" = "~" ]]; then
  _path="${HOME}${raw_path:1:}"
else
  _path="${raw_path}"
fi