How to manually expand a special variable (ex: ~ tilde) in bash
Due to the nature of StackOverflow, I can't just make this answer unaccepted, but in the intervening 5 years since I posted this there have been far better answers than my admittedly rudimentary and pretty bad answer (I was young, don't kill me).
The other solutions in this thread are safer and better solutions. Preferably, I'd go with either of these two:
- Charle's Duffy's solution
- Håkon Hægland's solution
Original answer for historic purposes (but please don't use this)
If I'm not mistaken, "~"
will not be expanded by a bash script in that manner because it is treated as a literal string "~"
. You can force expansion via eval
like this.
#!/bin/bash
homedir=~
eval homedir=$homedir
echo $homedir # prints home path
Alternatively, just use ${HOME}
if you want the user's home directory.
Why is a tilde in a path not expanded in a shell script?
In the bash manual, note that brace expansion during parameter substitution, but not recursively:
The order of expansions is: brace expansion; tilde expansion, parameter and variable expansion, arithmetic expansion, and command substitution (done in a left-to-right fashion); word splitting; and filename expansion.
This implies that any tilde (or parameter references or command substitution) stored unexpanded in a bash variable will not automatically resolve. Your JAVA_HOME variable contains a literal tilde, so bash will not expand it automatically.
It is likely that your fix worked because tilde expansion does not apply in quotes:
$ echo "~"
~
$ echo ~
/home/jeffbowman
...but parameter expansion like $HOME
does occur in quotes. Replacing it with $HOME expands to your home directory during the assignment of JAVA_HOME.
FOO=~/bar # stores /home/jeffbowman/bar
FOO="~/bar" # stores ~/bar
FOO=$HOME/bar # stores /home/jeffbowman/bar
FOO="$HOME/bar" # stores /home/jeffbowman/bar
Though the better option is to ensure your assignment is correct, if you want to expand it manually, these SO questions have some good options:
- "Tilde expansion in quotes"
- "How to manually expand a special variable (ex: ~ tilde) in bash"
Tilde (~/) not working on if then statement in Shell script
Double quotes (really, any quotes) prevent ~
from being expanded. Use instead:
checkfile=~/mysql_backup/"$file"
...or, even better, use $HOME
in all scripts, and consider ~
to be a facility for interactive/human use only.
Stop tilde expansion in bash script arguments
It's not under the script's control. It's up to the user. They must quote the tilde to prevent it from being expanded. Options include:
./script.sh \~/docs
./script.sh '~/docs'
./script.sh "~"/docs
Unable to test whether a file exists in Bash
~
is only expanded by the shell if it's unquoted. When it's quoted it's a literal tilde symbol.
local fname=~/.bash_profile
Why use $HOME over ~ (tilde) in a shell script?
Tilde expansion doesn't work in some situations, like in the middle of strings like /foo/bar:~/baz
Bash tilde not expanding in certain arguments, such as --home_dir=~
bash
is somewhat mistakenly treating home_dir=~
as an assignment. As such, the ~
is eligible for expansion:
Each variable assignment is checked for unquoted tilde-prefixes immediately following a : or the first =. In these cases, tilde expansion is
also performed.
Since --home_dir
is not a valid identifier, that string is not mistaken for an assignment.
Arguably, you have uncovered a bug in bash
. (I say arguably, because if you use set -k
, then home_dir=~
is an assignment, even though it is after, not before, the command name.)
However, when in doubt, quote a string that is meant to be treated literally whether or not it is subject to any sort of shell processing.
echo '--home_dir=~'
Update: This is intentional, according to the maintainer, to allow assignment-like argument for commands like make
to take advantage of tilde-expansion. (And commands like export
, which for some reason I was thinking were special because they are builtins, but tilde expansion would have to occur before the actual command is necessarily known.)
Shell Script Tilde Expansion
You will probably need to eval the variable to have it substituted correctly. One example would be to simply do
caminho=`eval "echo $caminho"`
Keep in mind that this will break if caminho
contains semicolons or quotes, it will also treat backslashes as escaping, and if the data is untrusted, you need to take care that you're not the target of an injection attack.
Hope that helps.
How to use `~` inside a double quote path reference
A tilde is only expanded if it's unquoted. Quoting (or, equivalent, prepending a backslash) disables expansion and turns them into literal tildes.
It's permissible to begin and end quotes mid-argument. You can quote the spaces while leaving the tilde unquoted. These are all equivalent:
wc -l ~/"file name with spaces.txt"
wc -l ~/'file name with spaces'.txt
wc -l ~/file\ name\ with\ spaces.txt
Related Topics
Component Based Web Project Directory Layout with Git and Symlinks
Prohibit Unaligned Memory Accesses on X86/X86_64
Need to Intercept Hid Keyboard Events (And Then Block Them)
How to Increase the /Proc/Pid/Cmdline 4096 Byte Limit
How to Disable Socket Creation for a Linux Process, for Sandboxing
How to Forward Localhost Port on My Container to Localhost on My Host
How to Handle the Linux Socket Revents Pollerr, Pollhup and Pollnval
Keep Meteor Running on Amazon Ec2
Find All Files Matching 'Name' on Linux System, and Search with Them for 'Text'
Linux: Block Until a String Is Matched in a File ("Tail + Grep with Blocking")
How Does Copy_From_User from the Linux Kernel Work Internally
How to Rebuild Rootfs in Buildroot
What Makes a Kernel/Os Real-Time
Maintain File and Folder Permissions Inside Archives
Which Jdk's Distributions Can Run 'Javac -Source 1.6 -Target 1.5'
How to Find the Main Function's Entry Point of Elf Executable File Without Any Symbolic Information