2014-01-13 4 views
5

Я отладка странности со сценарием оболочки и интересно, есть ли у поняло, как «вилка» в Bash (&) работает, возможно, потому, что я обычно использую его в отдельных командах через терминал, например:Что происходит, когда я использую `&` с функцией в сценарии Bash?

[~me]$ someExecutable & 

Теперь в скрипт:

foo() { 
    echo "logic" 
} 

bar() { 
    echo "idic" 
} 

baz() { 
    echo "katra" 
} 

foo & 
bar 
baz 

Мое намерение для функции foo будет вызываться асинхронно, а затем оставшуюся часть сценария, чтобы продолжить выполнение в исходном контексте процесса.

Когда я выполнить этот пример сценария я сделать получить ожидаемый результат:

logic 
idic 
katra 

(то есть, только отдельные очевидные призывы к bar и baz, я вовсе не беспокоили относительное из трех линий вывода, которые, как я понимаю, могут различаться)

, но я могу ошибаться как выход, так и сам сценарий. Если это так, это, безусловно, объяснит странность, которую я вижу в своем реальном коде, и избавит меня от необходимости копать дальше.

Возможно ли, что в дочернем процессе после вызова foo сценарий разветвленной оболочки продолжит? Это означает, что оставшаяся часть моего сценария оболочки будет выполнена дважды?

Что происходит, когда я использую & как в сценарии Bash?

ответ

3

Амперсанд предназначен только для вызова функции foo() в вашем примере. Он не разветвляет весь скрипт. Только foo() запускается в отдельном потоке, который завершается, когда foo() заканчивается. bar() и baz() продолжают работать в одной и той же резьбе

+0

Спасибо, что я был после! –

+4

+1 для решения проблемы. Quibble: foo() работает в (асинхронном) * подселе *, который является отдельным * процессом *. – mklement0

1

Символ & указывает оболочке выполнить команду (или группу команд) в фоновом режиме.

Следующие команды выполняются немедленно.

В этом отношении нет опасности выполнить сценарий, поэтому он отличается от fork().

2

& в bash не является вилкой. Он сообщает bash, чтобы запустить команду в подоболочке и продолжить синтаксический анализ для других команд (вместо того, чтобы ждать завершения этой команды).

Таким образом, как вы и ожидали, он запускает «foo» в фоновом режиме и продолжает обрабатывать команду «bar» и «baz» в оболочке верхнего уровня. Не было разворачивания вызывающей оболочки, но «foo» запускался в фоновом режиме.

Таким образом, выход «foo» может произойти после бара или база в зависимости от его содержимого .. но поскольку он использует «эхо», который является оболочкой, к моменту создания фонового процесса «foo» , «echo» сразу же доступен для него: поэтому есть хорошие шансы, что вы видите его вывод до того, как вызывающая оболочка переходит к следующей команде, что, судя по всему, происходит в вашем случае. (Но YMMV!Если «foo» вызывал тяжелую внешнюю команду, скорее всего, ее выход будет происходить позже)

В терминале это почти то же самое: вы можете рассмотреть окно терминала с приглашением оболочки в качестве файлового скрипта для этого shell, что оболочка входа читает «по мере ввода». Поведение почти одинаково.

+0

Я не беспокоюсь о порядке вывода, только чтобы получить только три строки. –

+0

Так же, как если бы вы ввели его в терминал. Но я догадываюсь, что вы уже нащупали это: все это спотыкается: '&' не является вилкой, т. Е. Не разветвляет вызывающую оболочку (или скорее shell + script). Оболочка запускает команду в отдельном процессе, а затем обрабатывает ее в фоновом режиме, вместо того, чтобы ждать ее завершения до продолжения. Ссылка http://web.mit.edu/gnu/doc/html/features_5.html –

+0

Скопируйте это. Это означает, что мой инстинкт об этом был правильным в течение всех этих лет, но также и то, что моя первоначальная ошибка остается необъяснимой :( –

1

Помимо того, что оператор управления & заставляет команду выполняться асинхронно в субоболочке 1, вы могли бы использовать Coprocesses контролировать выход.

Вместо вызова функции, говоря:

foo & 

говорят:

coproc fubar { foo; } 

, а затем читать вывод, говоря:

cat <&"${fubar[0]}" 

Это также позволит вам контролировать (следует ли испускать его после или перед другими функциями, такими как bar или baz).


Например, следующее:

foo() { 
    echo "logic1" 
    echo "logic2" 
} 

bar() { 
    echo "idic" 
} 

baz() { 
    echo "katra" 
} 

coproc fubar { foo; } 
bar 
baz 
cat <&"${fubar[0]}" 

будет производить:

idic 
katra 
logic1 
logic2 
+0

Хотя проблема OP не адресована напрямую, полезно знать о сопроцессах (bash 4+). – mklement0

0

На самом деле эта команда не запустить функцию Foo фона:

foo & 

Но по время ввода bar и baz foo уже завершил свой запуск и распечатал свой вывод на вашем терминале.

Однако, если вы запускаете ваши функции, как это, то вы заметите разницу:

foo & bar; baz 
[1] 46453 
idic 
katra 
logic 
[1]+ Done     foo 

Вот ваш идентификатор процесса может быть различным, чем моя, но вы можете видеть, что logic печатается в конце концов, после выхода из другого 2 функции.

+0

Я не беспокоюсь о порядке вывода; это то, что _only_ 'foo' запускается в фоновом режиме, не разворачивая весь скрипт. –

+0

Нет, я не подчеркивал порядок, я просто указывал, что функция 'foo' действительно была вызвана в фоновом режиме, а' bar', 'baz' вызывались нормально, поэтому порядок вывода был изменен. – anubhava

+0

Я знаю, что 'foo' запускается в фоновом режиме, но я хотел убедиться, что подпроцесс будет _only_ запускать' foo', и не продолжать с остальной частью скрипта (в результате остальная часть скрипта работает в два раза) –

Смежные вопросы