34

I need to umount something in my script, but sometimes it unmount's before all of the data has finished being copied and causes the umount to fail. I looked for a way to do a "blocking" umount, but I didn't find anything. So, I tried to write a script to loop until it could be unmounted, but it doesn't work.

while [ `sudo umount mount` ]
do
    sleep 0.1
done
rmdir mount

When run outputs:

umount: /home/evantandersen/mount: device is busy.
        (In some cases useful info about processes that use
         the device is found by lsof(8) or fuser(1))
rmdir: failed to remove `mount': Device or resource busy

Shouldn't it loop until the return value of sudo umount mount is 0, meaning it was successfully umounted?

2 Answers 2

72

The [ command is to evaluate conditional expressions. It's of no use here.

Because umount doesn't output anything on its standard output (the errors go to stderr), `sudo umount mount` expands to nothing.

So it's like:

while [ ]
do
  sleep 0.1
done

The [ command, when not passed any argument beside [ and ] returns false (a non-zero exit status), so you will not enter the loop.

Even if umount had output its errors on stdout, using the [ command would not have made sense, because the words resulting of that output would never have made up a valid conditional expression.

Here you want:

until sudo umount mount
do
  sleep 0.1
done

That is, you want to check the exit status of sudo/umount, not of a [ command.

If you wanted to check if umount output any error or warning on its stderr, that's where the [ could have been useful. The -n "some-string" is a conditional expression recognised by the [ command to test whether "some-string" is empty or not, so something like:

while [ -n "$(sudo umount mount 2>&1 > /dev/null)" ]; do
  sleep 0.1
done

But looking for the presence of error or warning messages is generally a bad idea. The umount command tells us whether or not it succeeds with its exit code, that's much more reliable. It could succeed and still output some warning message. It could fail and not output an error (like when it's killed).

In this particular case, note that umount might fail because the directory is not mounted, and you would loop forever in that case, so you could try another approach like:

while mountpoint -q mount && ! sudo umount mount; do
  sleep 0.1
done

Or if "mount" may be mounted several times and you want to unmount them all:

while mountpoint -q mount; do
  sudo umount mount || sleep 0.1
done
3
  • Works, awesome! Jun 6, 2013 at 22:52
  • 3
    +1 for explaining the difference between using [, [[ or not. I wish typical man pages, GNU and/or TLDP examples about bash conditionals covered such detail
    – renoirb
    Jun 26, 2016 at 2:24
  • And what if it never unmounts? I think its never a good idea to have a loop without an emergency exit.
    – mgutt
    Nov 5, 2020 at 22:15
5

reusable function, and will timeout in 'n' seconds

_umount() {
    [[ $# -lt 2 ]] && { 
        echo "Usage: ${FUNCNAME} <timeout_secs> <mnt_point>"; return 1
    }
    timeout=$(($(date +%s) + ${1}))
    until umount "${2}" 2>/dev/null || [[ $(date +%s) -gt $timeout ]]; do
       :
    done
}

no need to sleep

2
  • 1
    [[...]] is ksh/bash/zsh specific, all of which have the $SECONDS special variable, so you could do: SECONDS=0; until umount... || ((SECONDS > $1)); do.. Aug 1, 2017 at 12:43
  • Keep in mind that a mount remount,ro command on a mips device anno 2009 with an Intenso Micro Line USB stick can take 23 or even 30+ seconds to complete.
    – Pro Backup
    Sep 3, 2018 at 17:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .