Функции выполняются как подпроцессы в Bash?


28

В Advanced Bash-Scripting Guide , в примере 27-4 , 7-я строка снизу, я прочитал это:

Функция выполняется как подпроцесс.

Я сделал тест в Bash, и кажется, что приведенное выше утверждение неверно.

Поиски на этом сайте, Bash Man, и моя поисковая система не проливают свет.

У вас есть ответ и вы хотели бы объяснить?


12
Как уже отмечалось, это руководство вводит в заблуждение до крайности. Вместо этого я рекомендую Wooledge Bash Guide .
Подстановочный

Ответы:


36

Расширенное руководство по написанию сценариев не всегда надежно, и его примеры сценариев содержат устаревшие методы, такие как использование устаревших обратных галочек для подстановки команд, т. Е. `command`Вместо $(command).

В данном конкретном случае это явно неправильно.

Раздел о функциях оболочки в (каноническом) руководстве по Bash однозначно утверждает, что

Функции оболочки выполняются в текущем контексте оболочки; не создан новый процесс для их интерпретации.


10
«Расширенное руководство по написанию сценариев, как правило, ненадежно». Очень верно.
John1024

1
Можете ли вы дать ссылки в поддержку вашего первого предложения?
Уилл Воусден

5
@WillVousden, как будет выглядеть ссылка здесь? Куча примеров технических недостатков руководства? Документ, в котором эксперты в сообществе bash ранее отмечали, что это ненадежно? Поможет ли это, если член stackoverflow с золотым значком в bash только что согласился в комментарии? : p
Кодзиро

3
@WillVousden Я не думаю, что то, что вы хотите, существует в самой надежной форме. В прошлом Мендель Купер обновлял и исправлял проблемы с руководством, но нет общедоступной системы отслеживания ошибок или списка ошибок. (Возможно, это самое ужасное заявление, которое я могу сделать.) Поэтому, когда мы находим изъян (видимый или реальный), все, что мы можем сделать, - это написать автору по электронной почте и надеяться на лучшее.
Кодзиро

3
@WillVousden, ... если вам нужна история о том, как долго в канале freenode #bash было достигнуто согласие о том, что следует избегать ABS, см. Wooledge.org/~greybot/meta/abs - второе поле в каждой строке это временная метка, а первым является имя пользователя; Я собираюсь надеяться, что утверждения о том, что имена пользователей, о которых идет речь, очень уважаемые люди, достаточно.
Чарльз Даффи

32

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

  • когда вы запускаете их в фоновом режиме с &
  • когда вы запускаете их как ссылку в конвейере

Перенаправления или дополнительные env. переменные не будут вызывать новый подоболочек:

hw(){
    echo hello world from $BASHPID
    echo var=$var
} 
var=42 hw >&2
echo $BASHPID  #unexports var=42 and restores stdout here

Если вы определяете функцию с круглыми скобками вместо фигурных скобок:

hw()(
  echo hello world from $BASHPID
)
hw 
echo $BASHPID

это всегда будет работать в новом процессе.

Подстановка команд $()также всегда создает процессы в bash (но не в ksh, если вы запускаете встроенные команды внутри него).


Я не знал f() (...), разрешено. Есть ли другие определения, кроме {...}и (...)? В Bash я еще не знаком с другими.
Томаш

1
@tomas Вы можете использовать function hw { echo hello world; } синтаксис (нет необходимости, ()если вы печатаете , functionи вы можете указать перенаправления сразу после финала }или )как в hw(){ echo error; } >&2. Вот и все.
PSkocik

2
Это ответ, о котором я сразу подумал, и он абсолютно правильный. Это следует голосовать как правильный ответ. f()(...)всегда выполняйте собственную оболочку, а f(){...}не выполняйте.
rexkogitans

11
Примечание: bash-функции принимают любую составную команду, поэтому foo() [[ x = x ]]допустимо и определение функции. Однако, если вы посмотрите на функцию с, type fooвы увидите, что это все еще синтаксический сахар для foo() { [[ x = x ]]; }. То же самое относится и к функциям subshell: bar() ( : )становится bar() { ( : ); }.
Кодзиро

1
@kojiro приятно +1. не знал этого
PSkocik

9

Рассматриваемая команда из этого примера выглядит следующим образом:

echo ${arrayZ[@]/%e/$(replacement)}

Пример позже заявляет:

#    $( ... ) is command substitution.
#    A function runs as a sub-process.

Будучи благотворительными для ABS Guide, они, очевидно, хотели написать, что функция выполняется внутри подстановки команд, а команда внутри подстановки команд выполняется в подоболочке .


Это очень вводит в заблуждение. Спасибо за вашу интерпретацию.
Томаш

5
@tomas "очень вводит в заблуждение". Да очень. В отличие от Руководства по АБС, Wiki Грега - отличный источник расширенной информации о bash.
John1024

1
Приветствия. Что вы думаете об этом: wiki.bash-hackers.org/start ?
Томаш

@ Томас Я не знаю из первых рук об этом.
John1024

2
@tomas, ... мое личное мнение о bash-hackers wiki - это отличный источник. Я не прошел через это всесторонне, как у меня вики Wooledge, но это имеет тенденцию быть точным и точно написанным.
Чарльз Даффи
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.