web-dev-qa-db-ja.com

Bashスクリプト-戻り値が0になるまでループする

スクリプトで何かをアンマウントする必要がありますが、すべてのデータのコピーが完了する前にアンマウントして、アンマウントが失敗することがあります。 「ブロッキング」アンマウントを行う方法を探しましたが、何も見つかりませんでした。そのため、アンマウントできるようになるまでループするスクリプトを作成しようとしましたが、機能しません。

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

出力を実行すると:

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

Sudo umount mountの戻り値が0になるまでループしないでください。つまり、正常にアンマウントされました。

25
charliehorse55

[コマンドは、条件式を評価するためのものです。ここでは役に立たない。

umountは標準出力に何も出力しないため(エラーはstderrに送られます)、`Sudo umount mount`は何も展開しません。

だからそれは次のようなものです:

while [ ]
do
  sleep 0.1
done

[コマンドは、[および]以外の引数が渡されない場合、false(ゼロ以外の終了ステータス)を返すため、ループに入ることができません。 。

umountがstdoutにエラーを出力したとしても、[コマンドを使用しても意味がありません。その結果として得られた単語が有効な条件式を構成することはなかったからです。

ここにあなたが欲しい:

until Sudo umount mount
do
  sleep 0.1
done

つまり、[コマンドではなく、Sudo/umountの終了ステータスを確認する必要があります。

umountがstderrにエラーまたは警告を出力したかどうかを確認したい場合は、[が役に立ちました。 -n "some-string"は、[コマンドによって認識される条件式であり、"some-string"が空かどうかをテストします。

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

しかし、エラーまたは警告メッセージの存在を探すことは、一般的に悪い考えです。 umountコマンドは、終了コードで成功するかどうかを示します。これは、はるかに信頼性が高くなります。それは成功し、いくつかの警告メッセージを出力します。失敗してエラーが出力されない可能性があります(強制終了されたときなど)。

この特定のケースでは、ディレクトリがマウントされていないためumountが失敗する可能性があり、その場合は永久にループするため、次のような別のアプローチを試すことができます。

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

または、「mount」が複数回マウントされ、それらすべてをアンマウントしたい場合:

while mountpoint -q mount; do
  Sudo umount mount || sleep 0.1
done
59

再利用可能な関数であり、「n」秒でタイムアウトします

_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
}

寝る必要はありません

5