问题
In my bash script, I'm running an external command that's stored in $cmd
variable. (It could be anything, even some simple bash oneliner.)
If ctrl+C is pressed while running the script, I want it to kill the currently running $cmd
but it should still continue running the main script. However, I would like to preserve the option to kill the main script with ctrl+C when the main script is running.
#!/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
Any idea how to do it some nice bash way?
Changes applied based on answers:
#! /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
Now, pressing ctrl+C while "Ooook1?" read will break the eval only after that read is done. (it will interrupt just before "Oook2") However it will interrupt "sleep 4" instantly.
In both cases it will do the right thing - it will just interrupt the eval subshell, so we're almost there - just that weird read behaviour..
回答1:
If you can afford having the eval
part run in a subshell, "all" you need to do is trap 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
Don't know if that will fit your specific need though.
$ ./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)
回答2:
You can determine whether the sleep command exited abnormally by examining the last exit status echo $?
. A non-zero status probably indicates Ctrl-C.
回答3:
No, read
is not an external command, it is internal builtin bash
command being executed in the same process as the other instructions. So at Ctrl-C all the process will be killed.
P.S. Yes. you can execute command in subshell. Something like this
#!/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
来源:https://stackoverflow.com/questions/9196094/bash-ctrlc-in-eval-not-interrupting-the-main-script