This question already has an answer here:

I'm using a dotfile manage software, named dotdrop. Using a config file named .env, contents like: git_folder="~/code/Git".

Also use a script to setup this dotfile tool before the first use of it, as follows,

#!/bin/bash

env1="~/Dropbox/.env"
env2="/mnt/d/Dropbox/.env"

if [ -f $env1 ]; then
    echo "Found dotdrop env file, installing dotfiles..."
    source $env1
    eval $(grep -v "^#" $env1) dotdrop --cfg=${git_folder}/dotfiles/config.yaml install
elif [ -f $env2 ]; then
    echo "Found dotdrop env file, installing dotfiles..."
    source $env2
    eval $(grep -v "^#" $env2) dotdrop --cfg=${git_folder}/dotfiles/config.yaml install
else echo "Pls sync environment files first!"
fi

If I store my config file at ~/Dropbox/.env, when I run the script, I just got "Pls sync environment files first!"(run in if condition is expected). If config file stored at /mnt/d/Dropbox/.env, the script will go through the elif condition, which is expected.

Find the reason until I run the script in dubug mode, and get the difference:

➜  scripts git:(master) ✗ bash -x dotdrop_setup.sh 
+ env1='~/Dropbox/.env'
+ env2=/mnt/d/Dropbox/.env
+ '[' -f '~/Dropbox/.env' ']'
+ '[' -f /mnt/d/Dropbox/.env ']'
+ echo 'Pls sync environment files first!'
Pls sync environment files first!

So, I think the difference between ~ and /home/user is the reason.

After I change ~ to /home/roach(roach is user name), it works.

➜  scripts git:(master) ✗ bash -x dotdrop_setup.sh
+ env1=/home/roach/Dropbox/.env
+ env2=/mnt/d/Dropbox/.env
+ '[' -f /home/roach/Dropbox/.env ']'
+ echo 'Found dotdrop env file, installing dotfiles...'
Found dotdrop env file, installing dotfiles...
+ source /home/roach/Dropbox/.env
++ git_folder='~/code/Git'
++ grep -v '^#' /home/roach/Dropbox/.env
+ eval git_folder='~/code/Git'
++ dotdrop '--cfg=~/code/Git/dotfiles/config.yaml' install
     _       _      _
  __| | ___ | |_ __| |_ __ ___  _ __
 / _` |/ _ \| __/ _` | '__/ _ \| '_ |
 \__,_|\___/ \__\__,_|_|  \___/| .__/  v0.22.0
                               |_|


0 dotfile(s) installed.

The debug shows '' surround + env1='~/Dropbox/.env' is removed which I think is the reason.

But, WHY?


Additional question,

alias dotdrop="eval $(grep -v "^#" $env1) /usr/bin/dotdrop --cfg=${git_folder}/dotfiles/config.yaml install" is a config add to bashrc, zshrc, etc. It doesn't work if I add it to my script directly!

Finally, found I have to add source $env,

So WHY it works in a bashrc file?

marked as duplicate by muru, Jeff Schaller, RalfFriedl, schily, Wouter Verhelst Oct 22 at 16:17

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • Are you running this script with some other user then user you mentioned in question? – Debian_yadav Oct 22 at 6:22
  • Hi, @Debian_yadav. I run with same user not sure for your meaning, so I updated some detail about this question. – roachsinai Oct 22 at 6:36
  • Hi, @JulienLopez. I think for this question the answer is Tilde (~) not expand inside double quotes not WHY Tilde (~) not expand inside double quotes?. Cause if I kown Tilde (~) not expand inside double quotes I will not ask this question. – roachsinai Oct 22 at 12:33
up vote 11 down vote accepted

~ is a shortcut for your home directory, but only when it appears at the beginning of a string outside quotes. The beginning of the right-hand side of an assignment operator is the beginning of a string, so env1=~/Dropbox/.env would work (or env1=~"/Dropbox/.env" or any number of variations). It sets env1 to /home/roach/Dropbox/.env. But env1="~/Dropbox/.env" sets env1 to the exact string ~/Dropbox/.env, which as a file name looks inside a directory with the one-character name ~ in the current directory.

Tilde is an abbreviation, not a wildcard. $env1 outside quotes expands wildcards in the value of env1, but it doesn't expand the tilde because the tilde is not a wildcard.

You can also use env1="$HOME/Dropbox/.env". This is equivalent to env1=~/Dropbox/.env. The character $ (dollar) has a special meaning inside double quotes (it's the same meaning as outside quotes): it starts a variable substitution (or a command or arithmetic substitution). The character ~ (tilde), on the other hand, is just an ordinary character when it's inside quotes, even double quotes.


As for the alias, the reason it doesn't work in a bash script is that bash doesn't expand aliases in scripts by default. It won't work in any script unless you include or source the definition of the alias in that script, since aliases are a property of each shell instance. They aren't part of a process's environment.

The reason the alias works at all in your second script is that dotdrop itself expands the tilde when it reads its configuration value.

  • thanks for your answer! – roachsinai Oct 22 at 6:59
  • Also note, that in the assignment env1=~'/Dropbox/.env, the tilda replacement is performed before the statement execution (which is the assignment in this case), so in fact the variable env1 is really not assigned the tilda sign this way. If you want the tilda to be part of the value and expanded lateron, then leave it within the quotes and struggle with eval. – rexkogitans Oct 22 at 14:36

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