首页 > 解决方案 > Bash 陷阱 SIGINT 多次不起作用

问题描述

我不知道出了什么问题,但这个脚本不起作用。每次按 CTRL+C 时,它应该总是返回菜单。

#!/bin/bash

func_info()
{
    clear
    echo "This is info page."
    read -p "Press CTRL+C to back to menu or press enter exit..."
    exit
}

func_menu()
{
    clear
    trap - SIGINT
    echo "This is menu page."
    read -p "Press enter to go to info page..."
    trap func_menu SIGINT
    func_info
}

func_menu

它适用于第一次 CTRL+C 但第二次它不起作用。

我是新手,所以请不要评判我;)

任何帮助表示赞赏:) 谢谢。

编辑:

实际上,我发现这行得通

#!/bin/bash

func_info()
{
    clear
    echo "This is info page."
    read -p "Press CTRL+C to back to menu or press enter exit..."
    exit
}

func_menu()
{
    clear
    echo "This is menu page."
    read -p "Press enter to go to info page..."
    ( trap exit SIGINT; func_info )
    func_menu
}

func_menu

但是这样可以吗?

标签: bashbash-trap

解决方案


根据经验,您希望在信号处理期间尽可能少做。特别是如果您打算从信号中恢复而不是退出,通常最好简单地记录信号已发送,然后在“正常”代码中实际处理信号。

因此,与其为了导航而递归调用函数(在陷阱内),不如让我们跟踪当前页面并在循环中显示它。然后,所有 SIGINT 处理程序所要做的就是更新当前页面变量。

这是一个像您的示例一样的三页流程的工作演示(select用于导航,但如果您不喜欢,任何方法都可以使用select):

pages=(info news contact)
page=

info() { echo "For info, see the news page"; }
news() { echo "$(date +%Y-%m-%d): No news today"; }
contact() { echo "We cannot be reached."; }

while true; do
  trap - SIGINT
  clear
  if [[ -n "$page" ]]; then
    trap 'page=; continue' SIGINT
    echo "This is the ${page} page"
    "$page" # invokes the function named $page
    ( read -p $'\nPress CTRL+C to go back to menu or press enter to exit...' )
    exit
  else
    echo "This is the menu page"
    echo "Select a page number and press enter to go there."
    select page in "${pages[@]}"; do
      if [[ -n "$page" ]]; then break; fi
    done
  fi
done
  • 在循环开始时清除陷阱,以便 ^C 从菜单页面退出脚本
  • 显示页面时,配置page在 SIGINT/^C 上重置的陷阱
  • read在一个子外壳中
    • 正如您所发现的,子shell 会有所帮助,因为 SIGINT/^C 会整体中断子shell,而不是read专门中断
    • 并且只有exit读取成功

试一试!它在我的系统上运行良好(Bash 4.3)


推荐阅读