Здесь мой рабочий код:
function IsJsonString(str) {
try {
var json = JSON.parse(str);
return (typeof json === 'object');
} catch (e) {
return false;
}
Ответ Тома Андерсона неплох, но kill $(cat $PIDFILE)
произойдет только в моей системе, если foo
закончен сам по себе или через Ctrl-C. Для меня работает следующее решение
while read g
do
if [[ $g =~ bar ]]
then
kill $!
fi
done < <(
exec foo 2> >(tee /dev/tty)
)
Мне удалось найти способ сделать это без PID-файлов или со-подпрограмм и таким образом, чтобы они работали во всех POSIX-совместимых оболочках (я пробовал bash
и dash
). По крайней мере, в системах, которые поддерживают /dev/fd/
, но это должно быть почти все из них.
Это немного запутанно, хотя, поэтому я не уверен, что это по вашему вкусу.
( # A
( # B
( /tmp/foo 2>&1 1>&3 & echo $! >&4 ) | # C
( tee /dev/fd/2 | ( grep -q bar && echo fin >&4 ) ) # D and E
) 4>&1 | ( # F
read CHILD
read STATUS
if [ "$STATUS" = fin ]; then
kill $CHILD
fi
)
) 3>&1
Чтобы объяснить многочисленные подоболочки, используемые здесь:
Тело A
работает с нормальным stdout, дублируемым до fd 3. Он запускает подоболочки B
и F
с выводом B
, поданным по каналу на stdin F
.
Тело B
работает с трубой из A
, дублированной на fd 4.
C
запускает вашу фактическую команду foo, при этом ее stderr подключается к трубе от C
до D
и ее stdout, дублируемое из fd 3; то есть восстанавливается на глобальном уровне. Затем он записывает PID foo
в fd 4; то есть к трубе, на которой подоболочка F
имеет свой stdin.
D
запускает команду tee
, получая из трубы любое foo
печатает на своем stderr. Он копирует этот вывод как на /dev/fd/2
(чтобы он отображался на глобальном stderr), так и на канал, подключенный к подоболочке E
.
E
greps для бара, а затем, когда найден , пишет fin
на fd 4, то есть на канал, который F
имеет на своем stdin. Обратите внимание на &&
, убедившись, что no fin
не записано, если grep встречает EOF, не найдя bar
.
F
, затем читает PID с C
и fin
с E
. Если финал fin
был правильно выведен, он убивает foo
.
EDIT: Исправлено отсутствие tee
для копирования stderr foo в реальный stderr.
foo
буферизует свой stderr, когда он подключен к трубе без его промывки?
– Dolda2000
31 December 2012 в 00:20
read STATUS
находится там, где F
ожидает, что grep найдет bar
. Кстати, вам не нужно удалять старые комментарии. :)
– Dolda2000
31 December 2012 в 00:22
Expect предназначен для принятия действий на основе вывода процесса. Самое простое решение - просто позволить Expect запустить процесс, а затем выйти, когда он увидит ожидаемый результат. Например:
expect -c 'set msg {Saw "foo" on stderr. Exiting process.}
spawn /bin/bash -c "echo foo >&2; sleep 10"
expect "foo" { puts $msg; exit }'
Если порожденный процесс заканчивается нормально (например, до появления «foo»), то и сценарий Expect также выйдет.
Я изначально написал способ сделать это, что связано с swizzling, но это было не очень хорошо. Некоторые из комментариев относятся к этой версии. Проверьте историю, если вам интересно.
Вот способ сделать это:
(PIDFILE=$(mktemp /tmp/foo.XXXXXX) && trap "rm $PIDFILE" 0 \
&& { foo \
2> >(tee >(grep -q bar && kill $(cat $PIDFILE)) >&2) \
& PID=$! && echo $PID >$PIDFILE ; wait $PID || true; })
Хорошее старомодное кошмарное топливо. Что здесь происходит?
mktemp
, и вызывает его PIDFILE
PIDFILE
, снова для hygeine foo
; это выполняется в составном заявлении, так что &
связывается с foo
, а не со всем предыдущим конвейером foo
в замену процесса, которая ждет bar
чтобы появиться, а затем убивает foo
(из которых более поздней) foo
в переменной, записываем его в файл с именем PIDFILE
, а затем ждите его, поэтому что вся команда ждет foo
, чтобы выйти, прежде чем выйти; || true
отбрасывает статус выхода ошибки foo
, когда это происходит. Код внутри замещения процесса работает следующим образом:
tee
входной сигнал (стандартная ошибка foo
), перенаправление стандартного вывода tee
на стандартную ошибку, так что стандартная ошибка foo
действительно появляется на стандартной ошибке grep -q
на который ищет указанный шаблон и выходит, как только он найдет его (или когда он достигнет конца потока), без печати чего-либо, после чего (если он нашел строку и успешно вышел) оболочка переходит к ... kill
процесс, PID которого зафиксирован в файле с именем PIDFILE
, а именно foo
grep && kill
внутрь подстановки процесса, которая получает 2>
из foo; который оставляет поток foo
невозмутимым и будет в целом проще.
– Tom Anderson
30 December 2012 в 22:35
-q
, grep
делает i> после нахождения первой совпадающей строки.
– Tom Anderson
30 December 2012 в 23:03