6

In my Bash script I have this line:

 mv -f $HOME_DIR/$dir $HOME_SAVE/BACKUP

The problem is when $dir is empty (no $dir directory) the mv command moved the directory $HOME_DIR. We want only to move the $dir directories.

How can I avoid this case?

I can use this:

ls $HOME_DIR | wc -l   
# and verify if the number is -gt 1

But this is not an elegant solution.

  • Please look at these tips and some examples of good titles and write meaningful titles. Not jumbles + of words with + screwball punctuation. – Gilles Dec 4 '14 at 23:31
8

You should use :

mv -f -- "$HOME_DIR/${dir:?}" "$HOME_SAVE/BACKUP/"

The expansion will fail, the script quit, and an error message will be emitted to stderr if $dir's value is empty.

You can even specify the message printed like:

mv -f -- "$HOME_DIR/${dir:?\$dir is UNSET or NULL!}" "$HOME_SAVE/BACKUP/"

Alternatively - and less ultimately - you can specify default and/or substitute values for $dir which will only be applied if it is :-unset or null or :+set and not null using a similar form. All of these examples - above and below - are representative of a few of several standard POSIX-specified parameter expansion forms.

In the below example when $dir is set and not null the first portion evaluates to your source directory, else to nothing at all and the second portion evaluates to its value if any, but if none it evals instead to your target dir. mv is specified to fail when its first and second args name the same pathname and so nothing is moved at all.

mv -f -- "${dir:+$HOME_DIR/}${dir:-$HOME_SAVE/BACKUP/}" "$HOME_SAVE/BACKUP/" 2>/dev/null

That is probably overkill though as I suppose:

mv -f -- "$HOME_DIR/$dir" ${dir:+"$HOME_SAVE/BACKUP/"} 2>/dev/null

...should do just as well - mv can't move anything nowhere. Note that in a POSIX-conforming shell the quotes even inside the {} curlies serve to protect the expansion because in that case it is not $dir's value expanded but instead ${dir:+word} word's value expanded. Putting them within the braces serves to eval the expansion to nothing at all - not even a null string - when ${dir} is unset or null. That probably doesn't matter really - I'm fairly certain a null filename is invalid pretty much everywhere - but it's how I usually do it. This is not safe to do with ${dir:-"word"} however - in that case you would get either ${dir}'s unquoted expansion or word's quoted expansion.

You might also optionally invoke the -interactive option to mv only if $dir is null like:

mv "-i${dir:+f}" -- "$HOME_DIR/$dir" "$HOME_SAVE/BACKUP/" </dev/tty

...and so you would be sure at least not to accidentally overwrite any files in .../BACKUP without someone first pressing a y (or whatever) at the terminal.

  • 1
    Moving /dev/null will either fail (from an account without write permission to /dev) or damage the system. Both ways it sounds like a rather bad idea. – Emil Jeřábek Dec 4 '14 at 15:57
  • @EmilJeřábek - it will fail almost certainly. not sure how it would damage the system though - its just a dev node. could you expand on this please? – mikeserv Dec 4 '14 at 16:00
  • 1
    If you happen to run this as root, it will move the device file to $HOME_SAVE/BACKUP, making it disappear for all the applications that expect /dev/null to exist. Actually, I’m not sure what happens if /dev is managed by devfs or similar (I’m on an old system at the moment), but it sounds dangerous enough even to try it for no good reason. – Emil Jeřábek Dec 4 '14 at 16:09
  • @EmilJeřábek yes - so apps expecting /dev/null get ebadf rather than eof. not terrible. i only used it in the definition because it is one of a very few paths guaranteed by posix to exist - and so it cannot be some sensitive file or another that is not spec'd - and, among those, i considered it the least likely to cause trouble - though i will admit it might be an issue causing the need to reboot - or else to mknod it again, i guess - in some scenarios - though i think that is the worst it might get. – mikeserv Dec 4 '14 at 16:14
  • 1
    So you consider it adequate that a script may potentially make unrelated applications fail, and break the very POSIX guarantee that you quote? Let alone the fact that it is not even reliable, as $HOME_DIR may easily be more than two directories deep, in which case it may access a completely different file? – Emil Jeřábek Dec 4 '14 at 16:30
5

POSIXly:

[ -n "$dir" ] && mv -f -- "$HOME_DIR/$dir" "$HOME_SAVE/BACKUP"

or:

[ -d "${dir:+$HOME_DIR/$dir}" ] && ...
  • 1
    That doesn't solve the problem when $dir is empty. – Stéphane Chazelas Dec 4 '14 at 12:15
  • 1
    Yeah, I switch to -n for more simple version. – cuonglm Dec 4 '14 at 12:23
  • but shuld be like this [ -n $HOME_DIR/$dir ] ..... ( and if $dir is null the it will true because $HOME_DIR isnt null ) – maihabunash Dec 4 '14 at 12:39
  • @maihabunash - i dont think so - the point is to verify a null or not null - the test should always fail when $dir is null. – mikeserv Dec 4 '14 at 12:53
  • same thing here, too, huh? somebody ambled through and upvoted correction comments that no longer apply. silly. – mikeserv Dec 5 '14 at 13:49
3

Test if the dir variable is empty ([[ -z $dir ]]):

[[ -z $dir ]] || mv -t "$HOME_SAVE/BACKUP" "$HOME_DIR/$dir"
  • need to set afull PATH as [[ -z $HOME_DIR/$dir ]] ( but if $dir is empty then it will be anyway not null because $HOME_DIR ) – maihabunash Dec 4 '14 at 12:42
  • @maihabunash That test would always fail because of /. – muru Dec 4 '14 at 12:47
3

You can use this:

mv -f -- "$HOME_DIR/./$dir" "$HOME_SAVE/BACKUP/"

If $dir is empty, this will give a "Device or resource busy" error.

However, this is a bit of a hack.

  • thats pretty clever. i like hacks. – mikeserv Dec 4 '14 at 12:31

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.