Bash scripting - loop hasta que el valor de retorno sea 0

25

Necesito desmontar algo en mi script, pero a veces se desmonta antes de que todos los datos hayan terminado de copiarse y hace que el desmontaje falle. Busqué una manera de hacer un "bloqueo", pero no encontré nada. Entonces, intenté escribir un script para hacer un bucle hasta que pudiera desmontarse, pero no funciona.

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

Cuando se ejecutan salidas:

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

¿No debería sudo umount mountrepetirse hasta que el valor de retorno de sea ​​0, lo que significa que se desmontó con éxito?

charliehorse55
fuente

Respuestas:

59

El [comando es evaluar expresiones condicionales. No sirve de nada aquí.

Debido a umountque no muestra nada en su salida estándar (los errores van a stderr), se `sudo umount mount`expande a nada.

Entonces es como:

while [ ]
do
  sleep 0.1
done

El [comando, cuando no pasa ningún argumento al lado [y ]devuelve falso (un estado de salida distinto de cero), por lo que no ingresará al bucle.

Incluso si umounthubiera producido sus errores en stdout, usar el [comando no habría tenido sentido, porque las palabras resultantes de esa salida nunca habrían formado una expresión condicional válida.

Aquí quieres:

until sudo umount mount
do
  sleep 0.1
done

Es decir, desea verificar el estado de salida de sudo / umount, no de un [comando.

Si desea verificar si se umountproduce algún error o advertencia en su stderr, ahí es donde [podría haber sido útil. La -n "some-string"es una expresión condicional reconocida por el [comando para probar si "some-string"está vacía o no, así que algo como:

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

Pero buscar la presencia de mensajes de error o advertencia es generalmente una mala idea. El umount comando nos dice si tiene éxito o no con su código de salida, eso es mucho más confiable. Podría tener éxito y aún generar algún mensaje de advertencia. Podría fallar y no generar un error (como cuando se mata).

En este caso en particular, tenga en cuenta que umountpodría fallar porque el directorio no está montado, y en ese caso haría un bucle para siempre, por lo que podría intentar otro enfoque como:

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

O si "mount" puede montarse varias veces y desea desmontarlos a todos:

while mountpoint -q mount; do
  sudo umount mount || sleep 0.1
done
Stéphane Chazelas
fuente
Funciona, genial!
charliehorse55
1
1 para explicar la diferencia entre usar [, [[o no. Deseo páginas man típicos, GNU y / o ejemplos TLDP sobre los condicionales de bash cubiertos tanto detalle
renoirb
5

función reutilizable, y expirará en 'n' segundos

_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 hay necesidad de dormir

Christopher Barry
fuente
1
[[...]]es ksh/ bash/ zshespecífico, todos los cuales tienen la $SECONDSvariable especial, por lo que podría hacer:SECONDS=0; until umount... || ((SECONDS > $1)); do..
Stéphane Chazelas
Tenga en cuenta que un mount remount,rocomando en un dispositivo mips en el año 2009 con una memoria USB Intenso Micro Line puede tardar 23 o incluso más de 30 segundos en completarse.
Pro Backup