Script Bash - loop até o valor de retorno ser 0

25

Preciso desmontar algo no meu script, mas às vezes desmontar antes que todos os dados terminem de serem copiados e causar falha na desmontagem. Procurei uma maneira de fazer uma quantia de "bloqueio", mas não encontrei nada. Então, tentei escrever um script para fazer um loop até poder ser desmontado, mas não funciona.

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

Quando executar saídas:

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

Ele não deveria fazer um loop até que o valor de retorno sudo umount mountseja 0, significando que ele foi desmontado com sucesso?

charliehorse55
fonte

Respostas:

59

O [comando é avaliar expressões condicionais. É inútil aqui.

Como umountnão produz nada em sua saída padrão (os erros vão para stderr), `sudo umount mount`expande para nada.

Então é assim:

while [ ]
do
  sleep 0.1
done

O [comando, quando não passado nenhum argumento ao lado [e ]retorna false (um status de saída diferente de zero), portanto você não entrará no loop.

Mesmo se umounttivesse produzido seus erros no stdout, o uso do [comando não faria sentido, porque as palavras resultantes dessa saída nunca formariam uma expressão condicional válida.

Aqui você quer:

until sudo umount mount
do
  sleep 0.1
done

Ou seja, você deseja verificar o status de saída de sudo / umount, não de um [comando.

Se você quiser verificar se há umountalgum erro ou aviso em seu stderr, é aí que [poderia ter sido útil. O -n "some-string"é uma expressão condicional reconhecida pelo [comando para testar se "some-string"está vazio ou não, então algo como:

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

Mas procurar a presença de mensagens de erro ou aviso geralmente é uma má ideia. O umount comando nos diz se é bem-sucedido ou não com seu código de saída, isso é muito mais confiável. Pode ter sucesso e ainda gerar alguma mensagem de aviso. Pode falhar e não gerar um erro (como quando é morto).

Nesse caso específico, observe que umountpode falhar porque o diretório não está montado, e você faria um loop para sempre nesse caso, para tentar outra abordagem como:

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

Ou se "mount" pode ser montado várias vezes e você deseja desmontar todos eles:

while mountpoint -q mount; do
  sudo umount mount || sleep 0.1
done
Stéphane Chazelas
fonte
Works, awesome!
charliehorse55
11
1 para explicar a diferença entre a utilização [, [[ou não. Desejo páginas man típicos, GNU e / ou exemplos TLDP cerca condicionais festança coberto tal detalhe
renoirb
5

função reutilizável e atingirá o tempo limite em '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
}

não precisa dormir

Christopher Barry
fonte
11
[[...]]é ksh/ bash/ zshespecífico, todos os que têm a $SECONDSvariável especial, assim que você poderia fazer:SECONDS=0; until umount... || ((SECONDS > $1)); do..
Stéphane Chazelas
Lembre-se de que um mount remount,rocomando em um dispositivo mips no ano de 2009 com um dispositivo USB Intenso Micro Line pode levar 23 ou até mais de 30 segundos para ser concluído.
Pro Backup