在退出屏幕之前如何获得确认?

在退出屏幕之前如何获得确认?

如何在退出屏幕之前获得确认(在命令行上键入 exit 时)。这可能吗?

答案1

我通过exit用函数屏蔽命令来解决这个问题;该函数检查您是否在屏幕内,以及您是否是该屏幕进程中剩下的唯一子进程。

exit() {
  if  [[ "$(ps -o pid= --ppid "$(ps -o ppid= -p "$$")" | wc -l)" -eq 1 ]]
  then
    read -p "Warning: you are in the last screen window; do you really want to exit? (y/n) "
    case $REPLY in
        (y*) command exit "$@" ;;
    esac
  else
    # not within screen at all, or not within the last screen window
    command exit "$@"
  fi
}

您必须将该函数作为您的(bash)配置文件的一部分包含在内,例如~/.bash_profile.当启动 screen 时,它将(除非另有说明)启动 $SHELL 的一个实例。该 shell 将是 screen 进程的子进程。从子 shell 退出时,上面的代码会检查有多少进程是当前 shell 父进程的子进程。从里到外:

  • $(ps -o ppid= -p "$$")-- 询问=当前进程的父 PID(添加抑制标题行) ( $$)
  • $(ps -o pid= --ppid ... | wc -l)-- 请求 PID 列表(同样不带标头),其父 PID 是我们的父级,然后计算输出的行数

如果看起来我们是屏幕会话的最后一个子进程,它会提示确认;如果响应以字母 开头y,则函数调用“real”exit命令退出 shell;否则,函数结束而不退出 shell。

如果我们不是最后一个子进程,该函数将继续执行并正常退出。

我开发这个时需要注意几点:

  • 我最初进行了更多测试,if看看我们是否在屏幕会话中,包括查看是否STY已填充以及是否SHLVL大于 1。屏幕设置 STY,并且 bash 将增加 SLVL,但这些变量都不是只读的,所以这个测试还不够强大,没有什么用处。

  • screen 也设置了一个WINDOW变量,但检查它0并不可靠;您可以打开两个窗口,然后关闭 window 0,将 window1作为最后一个窗口。

  • 默认情况下,输入 EOF(通常为Control+ D)将导致 shell 立即退出,绕过此包装函数。我知道的最好的解决方法是将变量设置IGNOREEOF为某个非零值;但这只会延迟外壳不可避免的退出。

因为我在上面使用了很多 bash(和 GNU procutils)特定功能,所以我还想提供一个符合 POSIX 的解决方案。该ps行更改为一种ps ... | grep -c方案,以便捕获具有特定父 PID 的进程数。另一个更改是将 重新制作read -p为单独的提示符 和read

exit() {
  parent="$(ps -o ppid= -p $$)"
  if [ "$( ps -eo ppid= | grep -c "^ *${parent}\$" )" -eq 1 ]
  then
    printf "Warning: you are in the last screen window; do you really want to exit? (y/n) "
    read REPLY
    case $REPLY in
        (y*) command exit "$@" ;;
    esac
  else
    # not within screen at all, or not within the last screen window
    command exit "$@"
  fi
}

答案2

我假设你正在使用 bash。

are_u_sure(){
        read -n1 -p "Are you sure to exit? [y/N] "
        [ "$REPLY" != y ] && { echo; history -a; bash; }
}

trap are_u_sure EXIT

将其添加到您的 ~/.bashrc 中,然后每当您尝试退出 bash(输入 exit 或 ^D)时,系统都会提示您。除非你按“y”,否则你永远不会退出。

这样,我们就不必坚持屏幕魔法,因为我们可以在 bash 范围内完成它。

由于这种方法非常简单,它确实有一个缺陷,您将丢失之前输入的变量赋值。但也许我们可以为此努力。无论如何,您都可以修改此代码以满足您的需求。

答案3

我对我看到的任何其他解决方案都不太满意,所以我最终选择了这个(添加到 .bashrc 中):

exit_with_prompt() {
    printf "Do you really want to exit screen? (y/n) "
    read REPLY
    case $REPLY in
        (y*) command exit "$@" ;;
    esac
}

export IGNOREEOF=0
[[ $(type -t exit) == "alias" ]] && unalias exit
[[ $(type -t logout) == "alias" ]] && unalias logout

if grep -q "^screen\b" /proc/$PPID/comm; then
    export IGNOREEOF=2
    alias exit=exit_with_prompt
    alias logout=exit_with_prompt
fi

然后将其添加到 .screenrc:

shell -$SHELL

这与我通常做事的方式有点相反。它取消设置别名并重新启用 ctrl-d -> exit 正常,但它检查 bash 是否立即在 screen 实例内运行(具体来说,它检查父进程命令的开头是否是“screen”,然后是单词边界),然后它会禁用 ctrl-d/EOF 退出,并使用退出和注销的提示别名设置退出。

我使用它的时间不长,但到目前为止我对它的工作原理非常满意。

相关内容