【问题标题】:Recursive bash trap to call a function递归 bash 陷阱以调用函数
【发布时间】:2015-02-26 14:02:50
【问题描述】:

我创建了一个 bash 陷阱,它捕获 CTRL + C 并调用函数 ctrl_c。这个函数只是显示一条消息并启动一个计数器然后返回到主函数。

陷阱在第一次运行时工作正常,但如果再次尝试,它会显示 C^,尽管它确实禁用了 CTRL + C,但它不会再次调用该函数。

有没有办法将陷阱重置为像第一个实例一样运行。

提前致谢。

代码;

function ctrl_c() {
    clear
    echo "** Trapped CTRL-C"
    echo -n "Press [ Enter ] to continue."
    read
    for i in $(seq 1 5);
    do
            let timer="5 - $i + 1"
            clear
            echo "Returning to main menu in.. $timer"
            sleep 1
    done
    main
}

trap ctrl_c INT

【问题讨论】:

  • 请提供您的其余代码/一个最小的工作示例,您的 sn-p 不包含名为 main 的函数。
  • main只是一个菜单,用户可以选择选项1、2、3、4。这是第二次运行时调用函数ctrl_c失败的陷阱。
  • 你正在从被捕获的 ctrl_c 运行 main,所以你仍然在函数内部,并且当 ctrl_c 已经被捕获时无法捕获它。尽管你可以使用 trap - INT 来重置陷阱
  • 捕获后如何运行 main ?我尝试在函数 ctrl_c 的末尾使用 trap - INT。

标签: bash ctrl bash-trap


【解决方案1】:

将程序的控制权传递给信号处理程序并不是一个好主意。信号处理程序应该尽快完成并返回。因此,您可以在处理程序中启用标志变量,如下所示:

function ctrl_c() {
    flag=1
}

function trap_menu() {
    clear
    for i in $(seq 1 5);
    do
        let timer="5 - $i + 1"
        clear
        echo "Returning to main menu in.. $timer"
        sleep 1
    done
    flag=0
}

trap "ctrl_c" INT

flag=0
while ! [ $age ]; do
    echo -n "Enter your age> "
    while [ $flag -eq 0 ] && ! [ $age ]; do
        # Wait for one second
        read -t 1 age
    done
    if [ $flag -eq 1 ]; then trap_menu; fi
done

【讨论】:

  • 这里唯一明智的答案+1
【解决方案2】:

在中断处理程序运行时,信号总是被阻塞。在这段代码中,您的处理程序永远不会返回,因此信号保持阻塞状态。

不返回的信号处理程序通常是个坏主意。如果你只是想在一个信号之后重新启动一个函数,那么你可以在一个循环内的子shell中运行它并让处理程序退出,这将只从子shell退出。

编辑:根据 Adrian 的建议进行了更新。

    #!/bin/bash

    function ctrl_c() {
            clear
            echo "Trapped CTRL-C"
            echo
            for ((timer=5; timer>0; timer--)); do
                    printf "\rRetunring to main menu in $timer seconds"
                    sleep 1
            done
            exit 10
    }

    function main() {
            trap ctrl_c INT
            # Doing main stuff
            echo "Exiting normally"
            exit 0;
    }

    while ( main ); (($? == 10)); do :; done

【讨论】:

  • exit只是退出程序而不是子shell
  • @Seatter 不,它将退出子shell。试试吧。我在发布之前对其进行了测试。只要确保调用 main 用 ( ) 包围即可。
  • +1,这很有效,我正要发布几乎完全相同的内容。但我会将循环缩短为while (main); (($? == 10)); do :; done,从而摆脱循环外的( main )。冗余伤害了我的眼睛:-)
  • 顺便说一句,不要将echo 与选项一起使用——它不可移植。只需改用printf "\r<...>"
【解决方案3】:

您并没有“返回”到主函数,而是重新调用它,因此从技术上讲,您仍处于陷阱处理程序中。如果您在处理程序结束时排除“主”调用,bash 将在执行流程中断后返回到 NEXT 命令,您可以继续捕获更多中断。见Catch SIGINT in bash, handle AND ignore

function main() {
    echo sleeping...
    sleep 60
    main
}

function ctrl_c() {
    echo "** Trapped CTRL-C"
}

trap ctrl_c INT

main

在您的情况下,如果它只是一个失败的读取操作(从用户那里获取菜单选择),那么只需检查输入是否为空并循环返回以获取更多输入。

【讨论】:

    猜你喜欢
    • 2016-12-18
    • 1970-01-01
    • 1970-01-01
    • 2015-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多