How to manually expand a special variable (ex: ~ tilde) in bash

Viewed 103264

I have a variable in my bash script whose value is something like this:

~/a/b/c

Note that it is unexpanded tilde. When I do ls -lt on this variable (call it $VAR), I get no such directory. I want to let bash interpret/expand this variable without executing it. In other words, I want bash to run eval but not run the evaluated command. Is this possible in bash?

How did I manage to pass this into my script without expansion? I passed the argument in surrounding it with double quotes.

Try this command to see what I mean:

ls -lt "~"

This is exactly the situation I am in. I want the tilde to be expanded. In other words, what should I replace magic with to make these two commands identical:

ls -lt ~/abc/def/ghi

and

ls -lt $(magic "~/abc/def/ghi")

Note that ~/abc/def/ghi may or may not exist.

18 Answers

Here is a ridiculous solution:

$ echo "echo $var" | bash

An explanation of what this command does:

  1. create a new instance of bash, by... calling bash;
  2. take the string "echo $var" and substitute $var with the value of the variable (thus after the substitution the string will contain the tilde);
  3. take the string produced by step 2 and send it to the instance of bash created in step one, which we do here by calling echo and piping its output with the | character.

Basically the current bash instance we're running takes our place as the user of another bash instance and types in the command "echo ~..." for us.

why not delve straight into getting the user's home directory with getent?

$ getent passwd mike | cut -d: -f6
/users/mike

I have done this with variable parameter substitution after reading in the path using read -e (among others). So the user can tab-complete the path, and if the user enters a ~ path it gets sorted.

read -rep "Enter a path:  " -i "${testpath}" testpath 
testpath="${testpath/#~/${HOME}}" 
ls -al "${testpath}" 

The added benefit is that if there is no tilde nothing happens to the variable, and if there is a tilde but not in the first position it is also ignored.

(I include the -i for read since I use this in a loop so the user can fix the path if there is a problem.)

for some reason when the string is already quoted only perl saves the day

  #val="${val/#\~/$HOME}" # for some reason does not work !!
  val=$(echo $val|perl -ne 's|~|'$HOME'|g;print')

I think that

thepath=( ~/abc/def/ghi )

is easier than all the other solutions... or I am missing something? It works even if the path does not really exists.

Related