Bash, CTRL + C в eval не прерывая основной скрипт - PullRequest
5 голосов
/ 08 февраля 2012

В моем скрипте 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

Любая идея, какУдастся ли это как-то неплохо?

Изменения применяются на основе ответов:

#! /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

Теперь, нажимая ctrl + C , пока "Ooook1?""read сломает eval только после того, как это чтение завершено.(он прервется непосредственно перед "Oook2") Однако он немедленно прервет "сон 4".

В обоих случаях он будет делать правильные вещи - он просто прерывает eval subshell, так что мы почти на месте - просто странное поведение чтения ..

Ответы [ 3 ]

4 голосов
/ 08 февраля 2012

Если вы можете позволить себе выполнение части 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)
0 голосов
/ 08 февраля 2012

Нет, read не является внешней командой, это внутренняя встроенная команда bash, выполняемая в том же процессе, что и другие инструкции. Таким образом, при Ctrl-C весь процесс будет убит.

P.S. Да. Вы можете выполнить команду в subshell. Как то так

#!/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
0 голосов
/ 08 февраля 2012

Вы можете определить, вышла ли команда сна ненормально, проверив состояние последнего выхода echo $?. Ненулевое состояние, вероятно, указывает Ctrl-C.

...