0

Why ~ does not expand in $ ./foo.sh?

MYPATH_TO=~"/Documents 2/temp"
echo ~
echo "$MYPATH_TO"
mkdir "$MYPATH_TO"

when run in /home/mint/Documents 2 creates /home/mint/Documents 2/~/Documents 2/temp (echo outputs /home/mint ~/Documents 2/temp). I have read Why doesn't the tilde (~) expand inside double quotes? and put ~ outside of quotes, still does not expand, why?

ADDED: it does not expand because it is quoted in mkdir, but then how to script if I expect both spaces and symbols like ~ in path?

ADDED 2: when I tried mkdir w/out quotes for path w/out spaces:

MYPATH_TO=~"/Documents/temp"
mkdir $MYPATH_TO

I got error mkdir: cannot create directory ‘~/Documents/temp’: No such file or directory. Why? I have Documents in my home. I'm lost...

System: Linux Mint 19.2

Marisha
  • 343
  • 2
    Use $HOME instead of ~; then you don't have to worry about expansion. – ajgringo619 Oct 08 '19 at 01:09
  • The right side of = is considered "quoted". There is a high risk that it doesn't get expanded. One solution is to replace "~" with '$HOME' with ${MYPATH_TO/#~/'$HOME'} (in bash) or similar. –  Oct 08 '19 at 01:44
  • 2
    You also need to "unquote" the slash: MYPATH_TO=~/"Documents/temp" – Freddy Oct 08 '19 at 01:48

1 Answers1

2

A quick fix is to put the first slash outside the quoted part:

MYPATH_TO=~/"Documents 2/temp"
echo "$MYPATH_TO"

/home/user/Documents 2/temp

Another example:

bash -c 'a=~"/." b=~\/. c=~/. d=~/"."; echo "$a $b $c $d"'
~/. ~/. /home/user/. /home/user/.

Only $c and $d will have the tilde expanded in bash, dash, mksh and yash. ksh93 will also expand it in $a, and zsh in $a and $b.

According to the POSIX standard (emphasis mine):

A "tilde-prefix" consists of an unquoted <tilde> character at the beginning of a word, followed by all of the characters preceding the first unquoted <slash> in the word. In an assignment [...] multiple tilde-prefixes can be used: at the beginning of the word (that is, following the equal sign of the assignment), following any unquoted colon, or both. A tilde-prefix in an assignment is terminated by the first unquoted colon or slash.

This is just a pointless annoyance IMHO, because despite non-conforming to its letter, it's only ksh93 which implements what seems to be the intention, namely allowing user names containing slashes (you can escape them with backquotes in ksh93):

cat <<'EOT' >getpwnam.c
#include <pwd.h>
static struct passwd pwd = { "", "", 666, 666, "", "/hell", "" };
struct passwd *getpwnam(const char *name){ return &pwd; }
EOT
cc -Wall -shared getpwnam.c -o getpwnam.so
for sh in dash bash yash mksh zsh ksh93; do
    printf '%s\t' "$sh"
    LD_PRELOAD=./getpwnam.so HOME=nowhere \
      "$sh" -c 'echo ~q ~\/q ~"/q"'
done

dash    /hell ~/q ~/q
bash    /hell ~/q ~/q
yash    /hell ~/q ~/q
mksh    /hell ~/q ~/q
zsh     /hell nowhere/q nowhere/q
ksh93   /hell /hell nowhere/q