一定時間が経ってもユーザーがコマンドを入力しない場合

一定時間が経ってもユーザーがコマンドを入力しない場合

バラより以下の回答zshソリューションの場合


~/.bash_aliasesシステムを中断する前に、次のことを確認する必要があるとします。

function suspend()
{ #
    echo "Please confirm/cancel system suspension:"
    select confirmation in "confirm" "cancel"; do
        case ${confirmation} in
        confirm )
            echo "System suspending..."
            systemctl suspend
            break;;
        cancel )
            echo "Canceled suspension."
            break;;
        esac
    done
}

systemctl suspendユーザーが答えない場合は、実行を続けたいと思います。たとえば、10秒後にユーザー入力がない場合は、「confirm」ケースの内容が実行されます。

sleepサブシェルで次のことを試しました。

function suspend()
{ #
    flag_cancel=0
    echo "Please confirm/cancel system suspension:"
    (
    sleep 10 &&
        if [ $flag_cancel -eq 0 ]; then
        echo "System suspending..."
        systemctl suspend
        fi &
    )
    select confirmation in "confirm" "cancel"; do
    case ${confirmation} in
        confirm )
        echo "System suspending..."
        systemctl suspend
        break;;
        cancel )
        flag_cancel=1
        echo "Canceled suspension."
        break;;
    esac
    done
}

flag_cancelただし、値の変更は考慮されないため、コマンドは常に存在しますsleep

私が欲しいものを達成する方法は?

答え1

read実行時にユーザーから入力を受け取るには、コマンドを試してください。タイムアウトオプションがあるからです。

男性の場合:

-t timeout 入力の行全体をタイムアウト秒以内に読み取らないと、読み取りがタイムアウトし、戻りエラーが発生します。 timeout は、小数点の後に小数部がある 10 進数です。このオプションは、読み取りが端末、パイプ、またはその他の特殊ファイルから入力を読み取る場合にのみ有効です。通常のファイルから読み込むときは効果がありません。タイムアウトがゼロの場合、読み取りは指定されたファイル記述子から入力が可能な場合は成功を返し、そうでない場合は失敗を返します。タイムアウトを超えると、終了ステータスは128より大きくなります。

答え2

sleep呼び出しsleepとその後のテストが$flag_cancelバックグラウンド操作で発生するため、試行は機能しません。コードの主要部分の変数を変更しても、flag_cancelバックグラウンドサブシェルの変数の値には影響しません。コードは10秒後に無条件にシステムを停止します。

readselect代わりに数秒後にタイムアウトするという事実を使用できます。$TMOUTbash

以下は、最初のコード部分のトピックに対するバリエーションです。

suspend_maybe ()
{
        local PS3='Please confirm/cancel system suspension: '
        local TMOUT=10

        local do_suspend=true

        select confirmation in confirm cancel; do
                case $REPLY in
                        1)
                                # default case
                                break ;;
                        2)
                                do_suspend=false
                                break ;;
                        *)
                                echo 'Sorry, try again' >&2
                esac
        done

        if "$do_suspend"; then
                echo 'Suspending...'
                systemctl suspend
        else
                echo 'Will not suspend'
        fi
}

変更点:

  1. この関数は今呼び出されますsuspend_maybesuspendbash
  2. プロンプトを繰り返しますselectPS3
  3. 数秒select後にループがタイムアウトします$TMOUT
  4. 我々は明細書に数字を使用しますcase。これにより、すべての文字列を2回入力する必要がなくなります。値は$REPLYユーザーが入力したとおりに適用されます。
  5. selectユーザーが望むかどうかを知らせるループが必要です。キャンセルシステムが一時停止しました。一時停止をデフォルト操作として扱います。
  6. ループから離れると、selectユーザーはジョブのキャンセルを選択しない限りシステムを一時停止します。

同じことですが、入力ループをread次のドロップイン代替として使用しますselect

suspend_maybe ()
{
        local PS3='Confirm system suspension [y]/n: '
        local TMOUT=10

        local do_suspend=true

        while true; do
                if ! read -p "$PS3"; then
                        # timeout
                        break
                fi

                case $REPLY in
                        [yY]*)
                                # default case
                                break ;;
                        [nN]*)
                                do_suspend=false
                                break ;;
                        *)
                                echo 'Sorry, try again' >&2
                esac
        done

        if "$do_suspend"; then
                echo 'Suspending...'
                systemctl suspend
        else
                echo 'Will not suspend'
        fi
}

ここでは、ユーザーは一時停止nまたはN一時停止解除から始まる文字列を入力できます。タイムアウト、またはで始まる単語を入力またはread押すと、システムは一時停止します。yYCtrl+D

上記のループを使用すると、ユーザーがプロンプトに応答しないために一時停止が発生したときに特別なタスクを実行したい場合は、タイムアウト状況をより簡単にキャプチャできます。 - ステートメントは、呼び出しが失敗するたびに(または入力ストリームが閉じられたときに)実行されますbreakifread

答え3

一般的に選択できる選択肢は次timeoutのとおりです。GNUコアツール。組み込みコマンドのタイムアウトを設定していますが、外部ユーティリティはフルシェルを作成しなければこの操作を実行できないため、これは最良のオプションではありません。

if ! timeout 10 bash -c '
  select conf in yes no
  do
    case $conf in
      (yes) exit 1;;
      (no) exit 0;;
    esac
  done'
then
  echo 'Suspending'
fi

一部の外部ツール(おそらくグラフィカルツール)を介してユーザー入力を要求すると、もっと面白いかもしれません(これらのツールのいくつかは独自のタイムアウトメカニズムを実装しています)。

timeoutこのオプションは、--foregroundシェルプロンプトから直接呼び出さない場合(たとえば、subshel​​l:から呼び出す場合など( timeout ... ))、端末から読み込むときに必要です。

答え4

を使用してこれを行うこともできますat。利点:新しいツールを学ぶ必要がある場合は、最も汎用性の高いツールを学びます。at後でいつでもコマンドを予約してください。キューからスケジュールされたジョブを削除するために使用できますatrm

あなたの場合:

function suspend()
{ #
    JOBNO=$(echo "systemctl suspend" | at now + 0.2 seconds 2>&1 > /dev/null | awk '{print $2}')
    echo "Please confirm/cancel system suspension:"
    select confirmation in "confirm" "cancel"; do
    case ${confirmation} in
        confirm )
            echo "System suspending..."
            systemctl suspend
            break;;
        cancel )
            echo "Canceled suspension."
        break;;
    esac
    atrm $JOBNO
    done
}

関連情報