Setting a variable to ~/directory doesn't expand

I'm trying to setup a simple backup script with tar as you can see below:

#!/bin/bash TIME=`date +%F_%H-%M` FILENAME=backup-$TIME.tar.gz SRCDIR="~/PI/tutos/* ~/scripts/*" DESTDIR=/media/sf_ubuntuSharedFolder/backups tar cvpzf $FILENAME $SRCDIR 

However, the usage of $SRCDIR causes a tar error that I do not have if I just expand it myself.

[email protected]:~$ save tar: ~/PI/tutos/*: Cannot stat: No such file or directory tar: ~/scripts/*: Cannot stat: No such file or directory 

What is wrong here at using a shell variable? Otherwise, how can I pass a list of folders to tar in a single line?


The issue is that ~-expansion is not performed upon variable expansion (when you refer to that $SRCDIR unquoted) nor inside double quotes (when you assign that SRCDIR variable).

In leaving $SRCDIR unquoted, you're invoking the split+glob operator. That is the string that is stored in that scalar $SRCDIR variable (~/PI/tutos/* ~/scripts/*) is first split according to $IFS (blanks by default), and then each word undergoes globbing, that is are treated as patterns that expand to the list of matching files.

Because ~ is not expanded to your home directory there, that ~ is just treated like any other character, so it's just looking for files in the ~/PI/tutos directory, where ~ would be a directory in the current directory, which in your case doesn't exist.

Best here would be to make $SRCDIR an array and have the globs expanded at the time of the assignment:

SRCDIR=(~/PI/tutos/* ~/scripts/*) # ~ and globs expanded at this point
tar cvpzf "$FILENAME" "${SRCDIR[@]}"

Note that applying the split+glob operator on $FILENAME doesn't make sense, so we're disabling it by quoting $FILENAME.

Note that if ~/PI/tutos/* doesn't match, it will be left as-is, so you'd still get an error from tar. To avoid that, you could do:

shopt -s nullglob # remove non-matching globs
SRCDIR=(~/PI/tutos/* ~/scripts/*)
if ((${#SRCDIR[@]} != 0)); then
  tar cvpzf "$FILENAME" "${SRCDIR[@]}"

You may be tempted to do:

SRCDIR="$HOME/PI/tutos/* $HOME/scripts/*"
tar cvpzf "$FILENAME" $SRCDIR

As variables (such as $HOME) are expanded within double quotes, but I would advise against it as that wouldn't work properly if $HOME contains glob characters or characters of $IFS.

~s are expanded in variable assignments when not quoted and when at the start or following : (that's so that it works in assignments of variables like $PATH, $LD_LIBRARY_PATH... such as PATH=~/bin:~/sbin). So you may be tempted to do:

SRCDIR=~/PI/tutos/*:~/scripts/* # ~ (not globs) expanded here
tar cvpzf "$FILENAME" $SRCDIR

But that's the same as above, that won't work properly if $HOME contains $IFS characters (this time :, so very unlikely as /etc/passwd that defines your home directory is a colon-separated table) or glob characters.

Well, thank you very much for this clear and detailed explanation. Still a lots to learn, I appreciate the details and examples.

Merci !


Category: shell script Time: 2016-07-30 Views: 0

Related post

iOS development

Android development

Python development

JAVA development

Development language

PHP development

Ruby development


Front-end development


development tools

Open Platform

Javascript development

.NET development

cloud computing


Copyright (C), All Rights Reserved.

processed in 0.140 (s). 12 q(s)