5

在我的 bash 脚本中,我正在运行一个存储在$cmd变量中的外部命令。(可以是任何东西,甚至是一些简单的 bash oneliner。)

如果在运行脚本时按下ctrl+ C,我希望它终止当前正在运行的脚本,$cmd但它仍应继续运行主脚本。但是,我想保留在主脚本运行时使用ctrl+终止主脚本的选项C

#!/bin/bash
cmd='read -p "Ooook?" something; echo $something; sleep 4 ' 
while true; do
    echo "running cmd.."
    eval "$cmd"     # ctrl-C now should terminate the eval and print "done cmd"
    echo "done cmd"
    sleep 5         # ctrl-C now should terminate the main script
done

知道如何用一些不错的 bash 方式来做吗?

根据答案应用的更改:

#! /bin/bash

cmd='read -p "Ooook1?" something; read -p "Oook2?" ; echo $something; sleep 4 ' 
while true; do
    echo "running cmd.."
    trap "echo Interrupted" INT
    eval "($cmd)"     # ctrl-C now should terminate the eval and print "done cmd"
    trap - INT
    echo "done cmd"
    sleep 5         # ctrl-C now should terminate the main script
done

现在,在“Ooook1?”时按ctrl+ C只有在读取完成后,read 才会中断 eval。(它会在“Oook2”之前中断)但是它会立即中断“sleep 4”。

在这两种情况下,它都会做正确的事情——它只会中断 eval 子shell,所以我们快到了——只是那种奇怪的读取行为..

4

3 回答 3

4

如果您负担得起eval在子外壳中运行该部分,那么您需要做的“所有”就是捕获 SIGINT。

#! /bin/bash

cmd='read -p "Ooook1?" something; read -p "Oook2?" ; echo $something; sleep 4 ' 
while true; do
    echo "running cmd.."
    trap "echo Interrupted" INT
    eval "($cmd)"     # ctrl-C now should terminate the eval and print "done cmd"
    trap - INT
    echo "done cmd"
    sleep 5         # ctrl-C now should terminate the main script
done

不知道这是否适合您的特定需求。

$ ./t.sh 
running cmd..
Ooook1?^CInterrupted
done cmd
^C
$ ./t.sh 
running cmd..
Ooook1?qsdqs^CInterrupted
done cmd
^C
$ ./t.sh 
running cmd..
Ooook1?qsd
Oook2?^CInterrupted
done cmd
^C
$ 
GNU bash, version 4.1.9(2)-release (x86_64-pc-linux-gnu)
于 2012-02-08T15:31:49.413 回答
0

您可以通过检查最后的退出状态来确定 sleep 命令是否异常退出echo $?。非零状态可能表示 Ctrl-C。

于 2012-02-08T15:33:30.823 回答
0

不,read不是外部命令,它是bash在与其他指令相同的进程中执行的内部内置命令。因此,在 Ctrl-C 时,所有进程都将被终止。

PS是的。您可以在 subshel​​l 中执行命令。像这样的东西

#!/bin/bash
cmd='trap - INT; echo $$; read -p "Ooook?" something; echo $something; sleep 4 ' 
echo $$
while true; do
    echo "$cmd" > tmpfile
    echo "running cmd.."
    trap "" INT
    bash tmpfile
    rm tmpfile  
    trap - INT
    echo "done cmd"
    sleep 5         # ctrl-C now should terminate the main script   
done
于 2012-02-08T15:40:39.240 回答