
バラより以下の回答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秒後に無条件にシステムを停止します。
read
select
代わりに数秒後にタイムアウトするという事実を使用できます。$TMOUT
bash
以下は、最初のコード部分のトピックに対するバリエーションです。
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
}
変更点:
- この関数は今呼び出されます
suspend_maybe
。suspend
bash
- プロンプトを繰り返します
select
。PS3
- 数秒
select
後にループがタイムアウトします$TMOUT
。 - 我々は明細書に数字を使用します
case
。これにより、すべての文字列を2回入力する必要がなくなります。値は$REPLY
ユーザーが入力したとおりに適用されます。 select
ユーザーが望むかどうかを知らせるループが必要です。キャンセルシステムが一時停止しました。一時停止をデフォルト操作として扱います。- ループから離れると、
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
押すと、システムは一時停止します。y
Y
Ctrl+D
上記のループを使用すると、ユーザーがプロンプトに応答しないために一時停止が発生したときに特別なタスクを実行したい場合は、タイムアウト状況をより簡単にキャプチャできます。 - ステートメントは、呼び出しが失敗するたびに(または入力ストリームが閉じられたときに)実行されますbreak
。if
read
答え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
シェルプロンプトから直接呼び出さない場合(たとえば、subshell:から呼び出す場合など( 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
}