![在退出屏幕之前如何获得确认?](https://linux22.com/image/131295/%E5%9C%A8%E9%80%80%E5%87%BA%E5%B1%8F%E5%B9%95%E4%B9%8B%E5%89%8D%E5%A6%82%E4%BD%95%E8%8E%B7%E5%BE%97%E7%A1%AE%E8%AE%A4%EF%BC%9F.png)
如何在退出屏幕之前获得确认(在命令行上键入 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
并不可靠;您可以打开两个窗口,然后关闭 window0
,将 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 退出,并使用退出和注销的提示别名设置退出。
我使用它的时间不长,但到目前为止我对它的工作原理非常满意。