Is the tilde, `~` considered to be a relative path?
I'm trying to extract the different part of the Nvidia cuda library installer. I'm using the following command:
mkdir ~/Downloads/nvidia_installers
./cuda_6.5.14_linux_64.run -extract=~/Downloads/nvidia_installers
And I get the following message:
ERROR: extract: path must be absolute.
And when I type the command with the literal address of my home it work perfectly.
./cuda_6.5.14_linux_64.run -extract=/home/likewise-open/XXX/username/Downloads/nvidia_installers
I'm confused shouldn't ~ be the same of /home/likewise-open/XXX/username?
Tested:
./cuda_6.5.14_linux_64.run -extract=$HOME/Downloads/nvidia_installers
and it works, but I don't know why it doesn't allow ~
Solution 1:
Bash only expands a ~ if it's the beginning of a word. You can see this between the following commands:
$ echo -extract=~/test
-extract=~/test
oli@bert:~$ echo -extract ~/test
-extract /home/oli/test
Bash looks for standalone ~
characters and ~/
for this substitution. No other combination or quoted version will work.
$HOME
works because variable substitutions are more robust (the $
is a special character whereas ~
is very much less so):
$ echo Thisisastring${HOME}awrawr
Thisisastring/home/oliawrawr
While we're talking about ~
, it actually has another couple of other substitution uses:
-
~+
the current working directory (read from$PWD
) -
~-
the previous working directory (read from$OLDPWD
)
As with plain ~
, these can have additional paths tacked on the end, and again, these have to be the prefix to a word or Bash will ignore them.
You can read more about this in man bash | less -p ' Tilde'
Solution 2:
Just fixing it
This command shows an error message "ERROR: extract: path must be absolute":
./cuda_6.5.14_linux_64.run -extract=~/Downloads/nvidia_installers
The error is not helpful - the programm was too confused already.
You already know the error is from the ~
, as it works with $HOME
instead.
The problem: ~
only gets replaced at the start of a word.
For example, this works with the tilde:
echo -extract ~/Downloads
If you need the option syntax with =
, using $HOME instead of ~
is the most clean solution;
echo -extract=$HOME/Downloads
The practice
What you should know:
There are special cases where ~
get's expanded when not at the beginning of a word: as part of a variable assignment, directly after the =
. Which is confusing here, of course.
The other important special case it for use with variables like PATH. In variable assignments, ~
is also expanded after :
, like after the first =
.
$ dir=~ sh -c 'echo D2: $dir'
D2: /home/user
$ sh -c 'echo D2: $dir' dir=~
D2:
$ echo Dir: $dir
Dir:
$ dir=~; sh -c 'echo D2: $dir'
D2:
$ echo Dir: $dir
Dir: /home/user
$ sh -c 'echo D2: $dir'; d3=~
D2:
$ echo d3: $d3
d3: /home/user
The meaning of the tilde
In a shell, ~
, the tilde, is not really a path. It is only replaced by a path, $HOME
, some times.
It is something like a shorthand, or abbreviation, provided by the shell.
It can not be used like a path in general, the shell "expands" it to a path only in very special places.
And even if it is expanded, it can be to something else than the home directory.
- It is only expanded at the beginning of a word, or in a variable assignment after a
:
or=
- It is only expanded if it is not inside quotes
- It is only expanded to
$HOME
if there are no further characters in the word before a/
The problem in the command line
According to this, the problem in your command is that the tilde in
-extract=~/Downloads/nvidia_installers
is not expanded, because it is not one of the cases listed. That's all.
The solution could be to make the tilde the first unquoted character of a word, with no other character before the next /
- that is just what you get when you use an option with a space before the option argument:
-extract ~/Downloads/nvidia_installers
Another solution would be to use $HOME
instead. In a script, that is usually the better choice.
-extract=$HOME/Downloads/nvidia_installers
The error message
But how does the error message"ERROR: extract: path must be absolute."
?
fit into all this?
We know that the tilde did not get expanded. That means the program got the argument text including the ~
, but without the /home/auser
as the path. That path is ~/Downloads/nvidia_installers
- but now there is no shell, so the tilde has no special meaning. It is just a normal directory name. And as every other path of the form foo/bar/baz
, it is a relative path
Other uses
If there are characters after the ~
, as in ~alice
- with all the other rules above applying - and there is a user names alice
, that is expanded to the home directory of alice
instead, say home/alice
.
Also, if you are bob
, ~
would expand to /home/bob
, and ~bob
would expand to the same.
The variant ~+
is expanded to the current directory, $PWD
To refer to the previous directory, where you were before the last cd
, you can use ~-
, which is expanded to $OLDPWD
.
If you use pushd
and popd
, instead of cd
, you will already know that the directory stack can be accessed like ~-2
.
Details
All the cases where ~
is expanded to a path are handeled by the shell. For other programs, ~
is just a normal filename character.
For the exact definition inside the shell, here is the relevant section of man bash
Note how replacing ~
by $HOME
is just one special case of many cases: "If this login name is the null string, the tilde is replaced with the value of the shell parameter HOME.":
Tilde Expansion
If a word begins with an unquoted tilde character (`~'), all of the charac‐
ters preceding the first unquoted slash (or all characters, if there is no
unquoted slash) are considered a tilde-prefix. If none of the characters
in the tilde-prefix are quoted, the characters in the tilde-prefix follow‐
ing the tilde are treated as a possible login name. If this login name is
the null string, the tilde is replaced with the value of the shell parame‐
ter HOME. If HOME is unset, the home directory of the user executing the
shell is substituted instead. Otherwise, the tilde-prefix is replaced with
the home directory associated with the specified login name.
If the tilde-prefix is a `~+', the value of the shell variable PWD replaces
the tilde-prefix. If the tilde-prefix is a `~-', the value of the shell
variable OLDPWD, if it is set, is substituted. If the characters following
the tilde in the tilde-prefix consist of a number N, optionally prefixed by
a `+' or a `-', the tilde-prefix is replaced with the corresponding element
from the directory stack, as it would be displayed by the dirs builtin
invoked with the tilde-prefix as an argument. If the characters following
the tilde in the tilde-prefix consist of a number without a leading `+' or
`-', `+' is assumed.
If the login name is invalid, or the tilde expansion fails, the word is
unchanged.
Each variable assignment is checked for unquoted tilde-prefixes immediately
following a : or the first =. In these cases, tilde expansion is also per‐
formed. Consequently, one may use filenames with tildes in assignments to
PATH, MAILPATH, and CDPATH, and the shell assigns the expanded value.