Поддерживает ли bash разветвление аналогично fork () в C?

25

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

Например, я хотел бы, чтобы существовал следующий скрипт bash:

echo $$
do_fork()
echo $$

Если этот bash-скрипт действительно существует, ожидаемый результат будет:

<ProcessA PID>
<ProcessB PID>
<ProcessA PID>

или

<ProcessA PID>
<ProcessA PID>
<ProcessB PID>

Есть ли что-то, что я могу поставить вместо do_fork (), чтобы получить такой вывод, или заставить скрипт bash выполнить C-подобный форк?

Кори Кляйн
источник

Ответы:

23

Да. Форкинг пишется &:

echo child & echo parent

Вас может смущать то, что $$это не PID процесса оболочки, а PID исходного процесса оболочки. Смысл создания этого способа заключается в том, что он $$является уникальным идентификатором для конкретного экземпляра сценария оболочки: он не изменяется во время выполнения сценария и отличается от $$любого другого параллельно выполняемого сценария. Один из способов получить фактический PID процесса оболочки - это sh -c 'echo $PPID'.

Поток управления в оболочке не такой, как C. Если в C вы бы написали

first(); fork(); second(); third();

тогда эквивалент оболочки

after_fork () { second; third; }
first; after_fork & after_fork

Простая форма оболочки first; child & parentсоответствует обычной C-идиоме

first(); if (fork()) parent(); else child();

&и $$существуют и ведут себя таким образом в каждой оболочке в стиле Борна и в (t) csh. $PPIDне существует в оригинальной оболочке Bourne, но находится в POSIX (так что это в ash, bash, ksh, zsh,…).

Жиль "ТАК - перестань быть злым"
источник
3
Но это в основном «форк + exec», а не просто форк.
Mattdm
@mattdm: а? &это вилка, нет никакого exec, вовлеченного. Fork + exec - это когда вы запускаете внешнюю команду.
Жиль "ТАК - перестань быть злым"
@mattdm: Ах, я думаю, что вижу то, к чему идет Кори. Нет exec, но два языка имеют разные потоки управления.
Жиль "ТАК - перестань быть злым"
1
@Gilles: оператор управления bash &запускает подоболочку, в которой выполняется данная команда. Вилка + отл. Вы не можете просто поставить &без предшествующей команды для выполнения.
Mattdm
5
Ну, если бы «Форкинг пишется по буквам &» было верным утверждением, вы могли бы поставить &строку самостоятельно. Но ты не можешь. Это не означает «развилка здесь». Это означает «выполнить предыдущую команду в фоновом режиме в подоболочке».
Mattdm
10

Да, это называется подоболочек . Код оболочки внутри скобки запускается как подоболочка (форк). Однако первая оболочка обычно ждет завершения работы ребенка. Вы можете сделать это асинхронным, используя &терминатор. Посмотрите это в действии с чем-то вроде этого:

#!/bin/bash

(sleep 2; echo "subsh 1")&
echo "topsh"

$ bash subsh.sh

Кит
источник
5
Скобки создают подоболочку, но это форк + ожидание. &это вилка одна. Если вы хотите выполнить более одного конвейера в дочернем процессе, достаточно использовать фигурные скобки (которые выполняют группировку, не создавая дочерний процесс):{ sleep 2; echo child; } &
Жиль "ТАК - перестать быть злым"
6

Нет никакого собственного bash (или, насколько мне известно, любого другого типичного * nix shell) способа сделать это. Есть много способов порождать разветвленные процессы, которые делают что-то еще асинхронно, но я не думаю, что есть что-то, что следует точной семантике системного вызова fork ().

Типичный подход заключается в том, чтобы ваш скрипт верхнего уровня порождал помощников, выполняющих только ту работу, которую вы хотите разделить. Если вы делаете $0 $@ &или что-то еще, вы начнете с самого начала снова и вам нужно как-то это выяснить.

Я на самом деле начинаю думать о нескольких умных способах, которыми можно сделать именно это ....

Но , прежде чем мой мозг слишком увлекся этим, я думаю, что довольно хорошее правило: если вы пытаетесь написать что-то в оболочке, и оно наполняется хитрыми трюками, и вы желаете больше языковых возможностей, пора переключаться на настоящий язык программирования .

mattdm
источник
2
Несмотря на то, что вы правильно поняли - синтаксис bash, возможно, сложен, и ему не хватает более элегантных структур данных и функций Perl или Python, bash настолько же реален, насколько и в своей области . Это предметно-ориентированный язык, и я бы сказал, даже лучше (более лаконично, проще), чем, например, Python во многих случаях. Можете ли вы управлять целым рядом систем и не знать Python? Да. Можете ли вы сделать это и не знать, что такое bash [программирование]? Я не хотел бы попробовать. После 30 лет программирования оболочки я говорю вам, что это настолько реально, насколько это возможно. И да, я говорю на Python. Но не путайте молодежь.
Майк С
2
Тем не менее, технически мне больше нравится этот ответ. Сказать, что «&» является ответом на вопрос пользователя, «разветвление в одной точке, чтобы запустить две копии одного и того же сценария», на мой взгляд, сбивает с толку. Согласно руководству по bash, «&» делает следующее: «... выполняет [заданную] команду в фоновом режиме в подоболочке». Он должен завершить команду, и он включает в себя форк (технически, в Linux, clone ()), но в этот момент две копии одного и того же скрипта не работают.
Майк С