Запустіть кілька команд і вбийте їх як одну в баш


51

Я хочу запустити кілька команд (процесів) на одній оболонці. Усі вони мають власний безперервний вихід і не зупиняються. Запуск їх у фонових перервах Ctrl- C. Я хотів би запустити їх як єдиний процес , щоб бути в змозі зупинити всі з них (подоболочка, може бути?) Ctrl- C.

Для конкретності, я хочу запустити тести одиниць mocha(режим перегляду), запустити сервер і запустити деяку попередню обробку файлів (режим перегляду) і побачити вихід кожного з них в одному вікні терміналу. В основному я хочу уникати використання якогось завдання бігуна.

Я можу це усвідомити, запустивши процеси у фоновому режимі ( &), але тоді мені потрібно викласти їх на перший план, щоб зупинити їх. Мені б хотілося, щоб вони завершили процес, і коли я зупиняю процес, він зупиняє його "дітей".


Чи повинні вони бігати одночасно або один за одним?
Мінікс

Так, процеси повинні працювати одночасно, але мені потрібно бачити вихід з кожного.
користувач1876909

Відповіді:


67

Для одночасного запуску команд можна використовувати &роздільник команд.

~$ command1 & command2 & command3

Це почнеться command1, потім запуститься у фоновому режимі. Те саме з command2. Потім воно починається command3нормально.

Вихід усіх команд буде зібраний разом, але якщо це не для вас проблема, це було б рішенням.

Якщо ви хочете отримати окремий погляд на вихід пізніше, ви можете передавати висновок кожної команди в tee, що дозволяє вам вказати файл для дзеркального виводу.

~$ command1 | tee 1.log & command2 | tee 2.log & command3 | tee 3.log

Вихід, ймовірно, буде дуже безладним. Щоб протистояти цьому, ви можете дати виводу кожної команди префікс, використовуючи sed.

~$ echo 'Output of command 1' | sed -e 's/^/[Command1] /' 
[Command1] Output of command 1

Тож якщо ми зведемо все це разом, отримаємо:

~$ command1 | tee 1.log | sed -e 's/^/[Command1] /' & command2 | tee 2.log | sed -e 's/^/[Command2] /' & command3 | tee 3.log | sed -e 's/^/[Command3] /'
[Command1] Starting command1
[Command2] Starting command2
[Command1] Finished
[Command3] Starting command3

Це дуже ідеалізована версія того, що ви, мабуть, збираєтесь побачити. Але це найкраще, про що я можу подумати зараз.

Якщо ви хочете зупинити їх усі одразу, можете скористатися вбудовою trap.

~$ trap 'kill %1; kill %2' SIGINT
~$ command1 & command2 & command3

Це буде виконуватися command1і command2у фоновому режимі, і command3на передньому плані, що дозволяє вбити його за допомогою Ctrl+ C.

Коли ви вбиваєте останній процес з Ctrl+ Cна kill %1; kill %2команди виконуються, тому що ми з'єднали їх виконання з прийомом на переривати СИГНАЛ, річ відправленого натисканням Ctrl+ C.

Вони відповідно вбивають 1-й та 2-й фонові процеси (ваші command1та command2). Не забудьте видалити пастку, після закінчення роботи з командами trap - SIGINT.

Повний монстр команди:

~$ trap 'kill %1; kill %2' SIGINT
~$ command1 | tee 1.log | sed -e 's/^/[Command1] /' & command2 | tee 2.log | sed -e 's/^/[Command2] /' & command3 | tee 3.log | sed -e 's/^/[Command3] /'

Можна, звичайно, подивитися на екран . Це дозволяє розділити консоль на стільки окремих консолей, скільки ви хочете. Таким чином, ви можете контролювати всі команди окремо, але в той же час.


3
Чекаю на всю критику. :)
Minix

2
Дякую. Це робить саме те, що я хотів (команда trap). Однак рішення має бути загорнене в сценарій для повторного використання.
користувач1876909

@ user1876909 Ось кістяк. Специфіка залежить від вас [1]. Радий, що можу допомогти. [1] pastebin.com/jKhtwF40
Minix

3
це досить розумне рішення, iv дізнався щось нове, bravo +1
mike-m

1
Це дивно. Мені доводиться багато копатися і вчитися з цієї відповіді.
ccnokes

20

Ви можете легко вбити безліч процесів одразу, якщо ви домовитеся запускати їх (і тільки їх) в одній групі процесів .

Linux надає утиліту setsidдля запуску програми в новій групі процесів (навіть у новому сеансі, але нас це не хвилює). (Це неможливо, але без цього складнішеsetsid .)

Ідентифікатор групи процесів (PGID) групи процесів - це ідентифікатор процесу вихідного батьківського процесу в групі. Щоб знищити всі процеси в групі процесів, передайте негатив PGID killсистемному виклику або команді. PGID залишається дійсним, навіть якщо початковий процес із цим PID загине (хоча це може бути трохи заплутано).

setsid sh -c 'command1 & command2 & command3' &
pgid=$!
echo "Background tasks are running in process group $pgid, kill with kill -TERM -$pgid"

Якщо ви запускаєте процеси у фоновому режимі з неінтерактивної оболонки, вони всі залишаться в групі процесів оболонки. Лише в інтерактивних оболонках фонові процеси протікають у власній групі процесів. Тому, якщо ви відщелите команди з неінтерактивної оболонки, яка залишається на передньому плані, Ctrl+ Cзнищить їх усіх. Використовуйте waitвбудований змусити оболонку чекати, поки всі команди вийдуть.

sh -c 'command1 & command2 & command3 & wait'
# Press Ctrl+C to kill them all

2
невизначена відповідь (метод внизу). Просте для розуміння та запам'ятовування.
Ніколя Маршалл

14

Я здивований, що цього ще немає, але моїм улюбленим способом цього є використання підшаровок з фоновими командами. Використання:

(command1 & command2 & command3)

Вихідний результат видно з обох, всі команди bash та зручності все ще доступні, і один Ctrl-cвбиває їх усіх. Зазвичай я використовую це для того, щоб одночасно запускати сервер файлових файлів клієнта та сервер резервного сервера, тому я можу їх легко вбити, коли захочу.

Як це працює, що command1і command2працює у фоновому режимі нової подоболочки , наприклад, і command3на передньому плані цього примірника, і подоболочка є те , що першим отримує сигнал Руйнівник від Ctrl-cнатискання клавіші. Це дуже схоже на запуск сценарію bash щодо того, кому належить який процес і коли фонові програми вбиваються.


Якщо ви додасте waitяк остаточну команду (команда3 у вашому прикладі), ви можете виконати очищення коду після натискання користувачем Ctrl-c.
dotnetCarpenter


-2

Ви можете використовувати pipe. Це одночасно запустить команди на обох кінцях труби. Ви також повинні мати можливість зупинити всі команди CTRL-Cтакож.

1st command | 2nd command | 3rd command

Якщо ви хочете виконувати команди одна за одною, ви можете скористатися методом @ serenesat.


Це передає вихід першої команди другому (і так далі), що тут не доречно, оскільки вихід першої команди повинен закінчитися на терміналі.
Жиль "ТАК - перестань бути злим"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.