18

This doesn't work:

$ ls "~/.wine/drive_c/tools/Family Tree v2.0"
ls: cannot access '~/.wine/drive_c/tools/Family Tree v2.0': No such file or directory

But this does:

$ ls "/home/daniel/.wine/drive_c/tools/Family Tree v2.0"
Dossiers                           Dossiers_orig   Infos.opt      Racines.exe  'Register OCX.bat'   racines.CNT
Dossiers-2019.11.03-11.46.tar.gz   Html            REGSVR32.exe   Racines.hlp   Uninst.isu          readme.txt

Given that ~ is supposed to be the same as /home/daniel, what's going on here?

  • 22
    @Pilot6 No, in both examples shown, the path is quoted. The problem is that quoting suppresses tilde expansion. (I've posted an answer.) – Eliah Kagan Dec 1 at 16:10
  • 2
    The expansion of ~ to your home directory is a function of the shell you're using (bash, csh, etc), which expands ~ to $HOME et al before actually invoking the command. But quoting (double and single) is used to tell the shell to act differently, e.g. to include any spaces (the most common use) or other unusual characters that might be interpreted by the shell (like !! for history access, or $ for variable access). So ls $A show the contents of the directory name stored in environment variable A, and ls '$A' shows the contents of the directory literally called $A – simpleuser Dec 2 at 5:35
  • 2
    Possible duplicate of Why can't I cd to a quoted tilde ('~')? – phuclv Dec 2 at 10:08
49

Quoting, even with double quotes, suppresses tilde expansion.

~ can be used as a path to your home directory in contexts where tilde expansion is performed. ~ is not like . or ... There aren't actually any entries in your filesystem called ~ that serve as alternate names for your home directory.

When ~ appears by itself or as the first component of a path, your shell expands it into an absolute path to your home directory. But this does not happen when ~ is quoted. Double quotes provide a weaker form of quoting than single quotes, which is important to some other kinds of expansion, such as parameter expansion (which expands $HOME). But even double quotes suppress tilde expansion.

Thus ~ was not expanded in this command, where it is quoted:

ls "~/.wine/drive_c/tools/Family Tree v2.0"

Fortunately, it is permitted to write an argument some of whose parts are quoted and some of whose parts are not. So you can put ~/ before the quotes, and still quote the rest:

ls ~/".wine/drive_c/tools/Family Tree v2.0"

Or, since parameter expansion is performed even in double quotes--but not in single quotes--you can use:

ls "$HOME/.wine/drive_c/tools/Family Tree v2.0"

(Technically that is different, in that even when the HOME environment variable is unset, some shells still try to figure out what your home directory is and expand ~ to it--and bash is one such shell. But it's both rare and inadvisable to have HOME unset.)


Further reading:

  • 2
    "Fortunately, it is permitted to write an argument some of whose parts are quoted and some of whose parts are not." It is even permitted to mix it arbitrarily - this is called string concatenation, e.g. ~/'.wine'"/driv"'e_c/'tools'Family Tree v2.0'. Just ~/ needs to be unquoted. – rexkogitans Dec 2 at 14:30
  • 2
    @rexkogitans: Terminology: It would be "string concatenation" in a language like C where string text must be quoted. But this is shell; formally it's just a consequence of the quote-removal rules. There never were separate strings to get concatenated. Quote removal of paired '' and "" quotes simply happens after word-splitting and all(?) expansions, including tilde. – Peter Cordes Dec 3 at 16:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.