如果用户没有输入一段时间后执行命令

如果用户没有输入一段时间后执行命令

下面这个答案对于 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秒后没有用户输入,则执行“确认”案例的内容。

sleep我在子 shell 中尝试了以下操作:

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 可以是小数点后带有小数部分的十进制数。仅当 read 正在从终端、管道或其他特殊文件读取输入时,此选项才有效;从常规文件读取时它没有效果。如果超时为 0,如果指定文件描述符上的输入可用,则 read 返回成功,否则返回失败。如果超过超时,则退出状态大于 128。

答案2

您的尝试sleep将不起作用,因为调用sleep和后续测试$flag_cancel发生在后台作业中。对代码主要部分中变量的任何更改flag_cancel都不会影响后台子 shell 中变量的值,并且代码将在 10 秒后无条件挂起系统。

read相反,您可以使用和在 中几秒select后超时的事实。$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_maybe因为.suspendbash
  2. 循环select用于PS3其提示。
  3. 循环在几秒钟select后超时$TMOUT
  4. 我们在声明中使用数字case。这样我们就不必将所有字符串输入两次。的值$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

使用上面的循环,可以更轻松地捕获超时情况,以防您在由于用户未响应提示而发生暂停时想要执行任何特殊操作。每当调用失败时(或者在输入流关闭时),都会触发 - 语句break中的。ifread

答案3

一般来说,您可以选择的替代方案timeoutGNU 核心工具。这不是最好的选择,因为我们正在为内置命令设置超时,而外部实用程序只能通过生成整个 shell 来完成此操作:

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

如果您要通过某些外部工具(可能是图形工具)请求用户输入,可能会更有趣(尽管其中有几个工具实现了自己的超时机制)。

请注意,当不直接从 shell 提示符调用时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
}

相关内容