Ваш kill
команда назад.
Как много команд UNIX, опции, которые запускаются с минус, должны быть на первом месте перед другими аргументами.
Если Вы пишете
kill -INT 0
это видит -INT
как опция, и отправляет SIGINT
кому: 0
(0
специальное число, означающее все процессы в группе текущего процесса).
Но если Вы пишете
kill 0 -INT
это видит 0
, решает, что больше нет опций, так использование SIGTERM
по умолчанию. И отправляет это группе текущего процесса, то же, как будто Вы сделали
kill -TERM 0 -INT
(это также попыталось бы отправить SIGTERM
кому: -INT
, который вызвал бы синтаксическую ошибку, но она отправляет SIGTERM
кому: 0
во-первых, и никогда не получает это далеко.)
Таким образом, Ваш основной сценарий получает a SIGTERM
прежде чем это доберется для выполнения wait
и echo DONE
.
Добавить
trap 'echo got SIGTERM' TERM
наверху, сразу после
trap 'killall' INT
и выполненный это снова для доказательства этого.
Как Stephane Chazelas указывает, Ваши второстепенные дети (process1
, и т.д.), проигнорирует SIGINT
по умолчанию.
В любом случае я думаю, отправляя SIGTERM
имел бы больше смысла.
Наконец, я не уверен ли kill -process group
как гарантируют, перейдет к детям сначала. Игнорирование сигналов, в то время как закрытие могло бы быть хорошей идеей.
Так попробуйте это:
#!/bin/bash
trap 'killall' INT
killall() {
trap '' INT TERM # ignore INT and TERM while shutting down
echo "**** Shutting down... ****" # added double quotes
kill -TERM 0 # fixed order, send TERM not INT
wait
echo DONE
}
./process1 &
./process2 &
./process3 &
cat # wait forever
cat foo bar
пример не то, что я имел в виду. Здесь cat
только имеет вход того и один вывод за один раз.
tee
пример: это производит ко всем аргументам плюс его стандартный вывод одновременно. Используя тот же вид схемы ASCII-творчества как в моем предыдущем ответе, вот то, как tee foo bar
похож, когда это работает в терминале.
+------------------+
| tee |
===|<stdin | +------------+
→ | | | terminal |
| stdout>|=========|<input |
| | → ##==|< |
| | || +------------+
| stderr>|=====##
| | →
| | +-------------+
| 3>|=======|> file "foo" |
| | → +-------------+
| | +-------------+
| 4>|=======|> file "bar" |
| | → +-------------+
| |
+------------------+
В этом примере, tee
отправляет “полезный” вывод на три канала: к терминалу (потому что это - то, где его стандартный вывод подключен с), и в два файла. Кроме того, tee
имеет еще один канал вывода для ошибок.
Программа обычно имеет три канала ввода-вывода, определенные их числом дескриптора файла:
Целью дескрипторов файлов 0, 1 и 2 является только вопрос конвенции — ничто не осуществляет это, программа не может попытаться записать в дескриптор файла 0 или читать из дескрипторов 1 и 2 — но это - конвенция, которая в значительной степени универсально сопровождается.
Если Вы запускаете программу от терминала, дескрипторы файлов 0, 1 и 2 начинаются подключенный к тому терминалу, если они не были перенаправлены. Другие дескрипторы файлов начинаются закрытый и будут использоваться, если программа открывает другие файлы.
В частности, все команды имеют два вывода: стандартный вывод (для полезной нагрузки команды, “полезного” вывода), и стандартная погрешность (для ошибки или информационных сообщений).
Конвейер в оболочке (command1 | command2 | command3 | …
) подключения стандартный вывод каждой команды к стандартному входу следующей команды. Стандартная погрешность всех команд переходит к терминалу (если не перенаправлено).
Оболочки обеспечивают способы перенаправить другие дескрипторы файлов. Вы, вероятно, встретились 2>&1
или 2>file
перенаправить стандартную погрешность. Посмотрите при использовании дополнительного дескриптора файла? и другие сообщения это связывается с для примеров манипуляций другими дескрипторами файлов.
Многофункциональные оболочки также предлагают замену процесса для обобщения перенаправления файла к переданным по каналу командам, так, чтобы Вы не были ограничены линейным каналом с каждой командой, вводящей сингл и единственный вывод.
Очень немного команд пытаются получить доступ к дескрипторам файлов выше 2, кроме того, после того, как они открылись, файл (открывающий файл выбирает свободный дескриптор файла и возвращает его число приложению). Одним примером является GnuPG, который ожидает считывать данные, чтобы зашифровать/дешифровать/подписать/проверить на его стандартном входе и записать результат в стандартный вывод. Этому можно сказать считать пароль на другом дескрипторе файла с --passphrase-fd
опция. GnuPG также имеет опции сообщить о данных состояния по другим дескрипторам файлов, таким образом, можно было произвести полезную нагрузку на stdout, сообщениях об ошибках на stderr и информации о статусе о другом дескрипторе файла. Вот пример, где вывод переданной по каналу команды используется в качестве пароля:
echo fjbeqsvfu | rot13 | gpg -d --passphrase-fd=3 3<&0 <file.encrypted >file.plaintext
Да. Например, cat foo bar | less
дает два исходных данные (нечто файла и панель файла) и производит их обоих к меньше. vim foo*
произведет все файлы, начинающиеся с нечто в энергию. После рассмотрения каждого файла можно затем переключиться на следующий вывод с: n (или: wn, если Вы изменили что-нибудь). Я думаю, что Gilles объяснил это очень хорошо. При использовании канала (|), он берет вывод одной команды, вводит его в другую команду и затем производит результат. Это - другой пример нескольких выводов.
find . -name "*.bak" -type f -print | xargs /bin/rm -f
Это ввело бы много файлов, передало бы аргументы по каналу xargs и затем произвело бы каждый процесс.
– Jeight
19.10.2013, 09:03
Команды могут иметь больше чем один поток вывода, и я не подразумеваю под записью в файлы или сокеты. Рассмотрите большинство инструментов GNU (например. grep
) та печать ошибки к stderr и ожидаемый вывод к stdout. В то время как в интерактивной оболочке оба объединяются (2> &1), можно все еще рассматривать их отдельно. Это не заканчивается там, так как можно использовать дополнительные дескрипторы файлов, если программа или блок кода поддерживают его.
Изобретенный пример:
{
grep NORMAL log.txt
grep WARN log.txt 1>&3
grep ERROR log.txt 1>&4
} 1> normals.txt 3> warnings.txt 4> errors.txt # 2>/dev/null