Зачем писать весь скрипт bash в функциях?

59

На работе я часто пишу сценарии bash. Мой руководитель предложил разбить весь сценарий на функции, как показано в следующем примере:

#!/bin/bash

# Configure variables
declare_variables() {
    noun=geese
    count=three
}

# Announce something
i_am_foo() {
    echo "I am foo"
    sleep 0.5
    echo "hear me roar!"
}

# Tell a joke
walk_into_bar() {
    echo "So these ${count} ${noun} walk into a bar..."
}

# Emulate a pendulum clock for a bit
do_baz() {
    for i in {1..6}; do
        expr $i % 2 >/dev/null && echo "tick" || echo "tock"
        sleep 1
    done
}

# Establish run order
main() {
    declare_variables
    i_am_foo
    walk_into_bar
    do_baz
}

main

Есть ли какая-либо причина, чтобы сделать это, кроме «читабельности», которая, я думаю, могла бы быть одинаково хорошо обоснована еще несколькими комментариями и небольшим межстрочным интервалом?

Делает ли это сценарий более эффективным (я бы ожидал обратного, если что-нибудь), или это облегчает изменение кода за пределами вышеупомянутого потенциала читабельности? Или это действительно просто стилистическое предпочтение?

Обратите внимание, что, хотя сценарий демонстрирует это не очень хорошо, «порядок выполнения» функций в наших реальных сценариях имеет тенденцию быть очень линейным - walk_into_barзависит от того, что i_am_fooсделано, и do_bazдействует от материала, установленного walk_into_bar- так что возможность произвольно поменять порядок выполнения - это не то, что мы обычно делаем. Например, вы бы не захотели вдруг поставить declare_variablesпосле walk_into_bar, что сломало бы вещи.

Пример того, как я написал бы вышеупомянутый сценарий, был бы:

#!/bin/bash

# Configure variables
noun=geese
count=three

# Announce something
echo "I am foo"
sleep 0.5
echo "hear me roar!"

# Tell a joke
echo "So these ${count} ${noun} walk into a bar..."

# Emulate a pendulum clock for a bit
for i in {1..6}; do
    expr $i % 2 >/dev/null && echo "tick" || echo "tock"
    sleep 1
done
Доктор Дж
источник
30
Мне нравится твой босс. В своих сценариях я также ставлю main()вверху и добавляю main "$@"внизу, чтобы вызвать его. Это позволяет вам сразу увидеть высокоуровневую логику скрипта при ее открытии.
Джон Кугельман поддерживает Монику
22
Я не согласен с представлением о том, что читаемость «может быть одинаково хорошо подтверждена еще несколькими комментариями и небольшим межстрочным интервалом». За исключением, может быть, для художественной литературы, я бы не хотел иметь дело с книгой, в которой нет оглавления и описательных названий для каждой главы и раздела. В языках программирования это такая удобочитаемость, которую могут обеспечить функции, а комментарии - нет.
Рифмоид
6
Обратите внимание, что переменные, объявленные в функциях, должны быть объявлены local- это обеспечивает переменную область действия, которая невероятно важна в любом нетривиальном скрипте.
Борис Паук
8
Я не согласен с вашим боссом. Если вам нужно разбить ваш скрипт на функции, вам, вероятно, не стоит писать сценарий оболочки. Напишите программу вместо.
el.pescado
6
Функции предназначены для процессов, которые повторяются в сценарии или в нескольких сценариях. Они также позволяют внедрять единые методологии. Например, используя функцию для записи в системный журнал. Пока все используют одну и ту же функцию, ваши записи в системном журнале более последовательны. Одноразовые функции, такие как ваш пример, без необходимости усложняют сценарий. В некоторых случаях они создают проблемы (переменная область видимости).
Ксалори

Ответы:

40

Я начал использовать тот же стиль программирования bash после прочтения поста Kfir Lavi в блоге «Defensive Bash Programming» . Он приводит немало веских причин, но лично я считаю их наиболее важными:

  • процедуры становятся описательными: гораздо легче понять, что должна делать конкретная часть кода. Вместо стены кода вы видите «О, find_log_errorsфункция читает этот файл журнала на наличие ошибок». Сравните это с нахождением целого ряда строк awk / grep / sed, которые используют бог знает, какой тип регулярных выражений в середине длинного скрипта - вы не представляете, что там происходит, если нет комментариев.

  • Вы можете отлаживать функции, заключая в set -xи set +x. Как только вы узнаете, что остальная часть кода работает нормально, вы можете использовать этот трюк, чтобы сосредоточиться на отладке только этой конкретной функции. Конечно, вы можете заключить части скрипта, но что, если это длинная часть? Проще сделать что-то вроде этого:

     set -x
     parse_process_list
     set +x
    
  • использование печати с cat <<- EOF . . . EOF. Я использовал его несколько раз, чтобы сделать свой код более профессиональным. Кроме того, parse_args()с getoptsфункцией довольно удобно. Опять же, это помогает с удобочитаемостью, вместо того, чтобы помещать все в сценарий как гигантскую стену текста. Это также удобно использовать повторно.

И, очевидно, это гораздо более читабельно для тех, кто знает C, Java или Vala, но имеет ограниченный опыт работы с bash. Что касается эффективности, то вы мало что можете сделать - сам bash не самый эффективный язык, и люди предпочитают perl и python, когда речь идет о скорости и эффективности. Тем не менее, вы можете niceфункцию:

nice -10 resource_hungry_function

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

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

Некоторые из примеров, где я использовал этот стиль:

Сергей Колодяжный
источник
3
Я не уверен, что вы должны принимать какие-либо предложения из этой статьи очень серьезно. Конечно, у него есть несколько хороших идей, но это явно не тот, кто использовал для сценариев оболочки. Ни одна переменная ни в одном из примеров не заключена в кавычки (!), И она предлагает использовать имена переменных UPPER CASE, что часто является очень плохой идеей, поскольку они могут конфликтовать с существующими переменными env. Ваши пункты в этом ответе имеют смысл, но связанная статья, кажется, была написана кем-то, кто просто привык к другим языкам и пытается навязать свой стиль на bash.
Тердон
1
@terdon Я вернулся к статье и перечитал ее. Единственное место, где автор упоминает именование переменных в верхнем регистре, это «Неизменяемые глобальные переменные». Если вы рассматриваете глобальные переменные как те, которые должны находиться в среде функции, то имеет смысл сделать их заглавными. Кроме того, в руководстве по bash не указывается соглашение для переменной. Даже здесь принятый ответ гласит: «обычно», и единственным «стандартом» является Google, который не представляет всю ИТ-индустрию.
Сергей Колодяжный
@terdon с другой стороны, я согласен на 100%, что цитирование переменных должно быть упомянуто в статье, и это также было отмечено в комментариях в блоге. Кроме того, я бы не стал судить кого-то, кто использует этот стиль кодирования, независимо от того, привыкли они к другому языку или нет. Весь этот вопрос и ответы ясно показывают, что в этом есть свои преимущества, и степень человека, к которому они привыкли к другому языку, здесь, вероятно, не имеет значения.
Сергей Колодяжный
1
@terdon хорошо, статья была размещена как часть "исходного" материала. Я мог бы опубликовать все как свое собственное мнение, но я просто должен был отдать должное тому, что кое-что из того, что я узнал из этой статьи, и что все это пришло из исследований во времени. Страничка автора с вопросами об ошибках показывает, что они имеют хороший опыт работы с Linux и IT в целом, поэтому я думаю, что статья не показывает этого на самом деле, но я верю в ваш опыт работы с Linux и сценариями оболочки, так что вы можете быть правы ,
Сергей Колодяжный
1
Это отличный ответ, но я также хотел бы добавить, что переменная область видимости в Bash - это просто прикольно. По этой причине я предпочитаю объявлять свои переменные внутри функций, используя localи вызывая все через main()функцию. Это делает вещи намного более управляемыми, и вы можете избежать потенциально грязной ситуации.
Хоусни
65

Читаемость это одно. Но есть нечто большее, чем модульность . ( Полумодуляризация может быть более правильной для функций.)

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

Другим преимуществом функций является возможность повторного использования . После того, как функция закодирована, ее можно применять несколько раз в сценарии. Вы также можете перенести его на другой скрипт.

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

Еще один момент, чтобы добавить. Как отмечает Etsitpab Nioliv в приведенном ниже комментарии, легко перенаправить из функций в единое целое. Но есть еще один аспект перенаправлений с функциями. А именно, перенаправления могут быть установлены вдоль определения функции. Например.:

f () { echo something; } > log

Теперь для вызова функций не требуется явного перенаправления.

$ f

Это может сэкономить много повторений, что снова повышает надежность и помогает поддерживать порядок.

Смотрите также

Tomasz
источник
55
Очень хороший ответ, хотя было бы намного лучше, если бы он был разбит на функции.
Пьер Арло
1
Возможно, добавьте, что функции позволяют импортировать этот скрипт в другой скрипт (с помощью sourceили . scriptname.sh, и использовать эти функции, как если бы они были в вашем новом скрипте.
SnakeDoc
Это уже описано в другом ответе.
Томаш
1
Я ценю это. Но я бы предпочел, чтобы другие люди тоже были важны.
Томаш
7
Сегодня я столкнулся со случаем, когда мне пришлось перенаправлять часть вывода скрипта в файл (чтобы отправить его по электронной почте), а не отражать его. Я просто должен был сделать myFunction >> myFile, чтобы перенаправить вывод нужных функций. Довольно удобно. Может быть актуальным.
Эцитпаб Ниолив
39

В своем комментарии я упомянул три преимущества функций:

  1. Их легче проверить и проверить правильность.

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

  3. Твой босс любит их.

И никогда не стоит недооценивать важность номера 3.

Я хотел бы затронуть еще одну проблему:

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

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

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

John1024
источник
Я бы сказал, что иногда разумно моделировать и применять эти зависимости против рефакторинга, чтобы избежать их (поскольку, если их достаточно, и они достаточно волосатые, это может привести к тому, что вещи больше не будут модульными в функционирует на всех). Очень сложный вариант использования когда-то вдохновил фреймворк именно на это .
Чарльз Даффи
4
То, что нужно разделить на функции, должно быть, но пример заходит слишком далеко. Я думаю, что единственное, что действительно мешает мне - это функция объявления переменных. Глобальные переменные, особенно статические, должны быть определены глобально в закомментированном разделе, посвященном этой цели. Динамические переменные должны быть локальными для функций, которые их используют и модифицируют.
Ксалори
@Xalorous Я видел практики, где глобальные переменные инициализируются в процедуре, в качестве промежуточного и быстрого шага перед разработкой процедуры, которая считывает их значение из внешнего файла ... Я согласен, что должно быть чище отделять определение и инициализации , но редко вы должны согнуть подвергнуться преимущество № 3;-)
Хастура
14

Вы разбиваете код на функции по той же причине, что и для C / C ++, python, perl, ruby ​​или любого другого кода языка программирования. Более глубокая причина - абстракция - вы инкапсулируете задачи более низкого уровня в примитивы (функции) более высокого уровня, так что вам не нужно беспокоиться о том, как все делается. В то же время код становится более читабельным (и обслуживаемым), а логика программы становится более понятной.

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

countermode
источник
Недооцененный ответ ИМХО. Вы предлагаете объявить переменные в mainфункции / методе, тогда?
Дэвид Табернеро М.
13

Хотя я полностью согласен с возможностью повторного использования , удобочитаемостью и деликатным целованием боссов, но есть еще одно преимущество функций в : переменная область видимости . Как показывает ЛДП :

#!/bin/bash
# ex62.sh: Global and local variables inside a function.

func ()
{
  local loc_var=23       # Declared as local variable.
  echo                   # Uses the 'local' builtin.
  echo "\"loc_var\" in function = $loc_var"
  global_var=999         # Not declared as local.
                         # Therefore, defaults to global. 
  echo "\"global_var\" in function = $global_var"
}  

func

# Now, to see if local variable "loc_var" exists outside the function.

echo
echo "\"loc_var\" outside function = $loc_var"
                                      # $loc_var outside function = 
                                      # No, $loc_var not visible globally.
echo "\"global_var\" outside function = $global_var"
                                      # $global_var outside function = 999
                                      # $global_var is visible globally.
echo                      

exit 0
#  In contrast to C, a Bash variable declared inside a function
#+ is local ONLY if declared as such.

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

Повторное использование часто означает создание общей библиотеки функций и sourceвнедрение этой библиотеки во все ваши сценарии. Это не поможет им работать быстрее, но поможет вам писать их быстрее.

птенцы
источник
1
Мало кто явно использует local, но я думаю, что большинство людей, пишущих сценарии, разбитые на функции, все еще следуют принципу разработки. Usign localтолько усложняет введение ошибок.
Во
localделает переменные доступными для функции и ее потомков, поэтому очень приятно иметь переменную, которая может передаваться из функции A, но недоступна для функции B, которая может хотеть иметь переменную с тем же именем, но с другим назначением. Так что это хорошо для определения объема, и, как сказал Во, - меньше ошибок
Сергей Колодяжный
10

Совершенно иная причина, нежели те, которые уже приведены в других ответах: одна из причин, по которой этот метод иногда используется, когда единственным не-определением оператора на верхнем уровне является вызов main, состоит в том, чтобы убедиться, что скрипт случайно не делает ничего неприятного если скрипт урезан. Сценарий может быть усечен, если он передается из процесса A в процесс B (оболочку), и процесс A завершается по любой причине до того, как он завершил написание всего сценария. Это особенно вероятно, если процесс A извлекает сценарий из удаленного ресурса. Хотя по соображениям безопасности это не очень хорошая идея, это то, что делается, и некоторые сценарии были изменены, чтобы предвидеть проблему.

HVD
источник
5
Интересно! Но меня беспокоит, что об этих вещах нужно заботиться в каждой из программ. С другой стороны, именно этот main()шаблон является обычным в Python, где каждый использует if __name__ == '__main__': main()в конце файла.
Мартин Уединг
1
Преимущество языка Python состоит в том, что он позволяет другим сценариям importиспользовать текущий сценарий без запуска main. Я полагаю, что подобный сторож может быть добавлен в скрипт bash
Джейк Кобб
@ Джейк Кобб Да. Теперь я делаю это во всех новых скриптах bash. У меня есть сценарий, который содержит базовую инфраструктуру функций, используемых всеми новыми сценариями. Этот сценарий может быть получен или выполнен. Если источник, его основная функция не выполняется. Обнаружение источника по сравнению с выполнением происходит через тот факт, что BASH_SOURCE содержит имя исполняемого сценария. Если он совпадает с основным сценарием, сценарий выполняется. В противном случае это источник.
DocSalvager
7

Процесс требует последовательности. Большинство задач являются последовательными. Нет смысла связываться с заказом.

Но самое главное в программировании, которое включает в себя сценарии, это тестирование. Тестирование, тестирование, тестирование. Какие тестовые сценарии у вас сейчас есть для проверки правильности ваших сценариев?

Ваш босс пытается помочь вам стать сценаристом и стать программистом. Это хорошее направление, чтобы войти. Люди, которые придут после вас, будут вам нравиться.

НО. Всегда помните свои ориентированные на процесс корни. Если имеет смысл упорядочить функции в той последовательности, в которой они обычно выполняются, сделайте это, по крайней мере, в качестве первого прохода.

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

Позже вы, возможно, поймете, что вы сейчас написали библиотеки небольших вспомогательных функций, которые вы используете во многих своих скриптах.

Деви Морган
источник
7

Как я продемонстрирую, комментарии и интервалы не могут приблизиться к удобочитаемости функций. Без функций вы не можете видеть лес за деревьями - большие проблемы скрываются среди множества деталей. Другими словами, люди не могут одновременно сосредоточиться на мелких деталях и на общей картине. Это может быть неочевидно в коротком сценарии; пока оно остается коротким, оно может быть достаточно читабельным. Программное обеспечение становится больше, но не меньше, и, безусловно, оно является частью всей системы программного обеспечения вашей компании, которая, безусловно, намного больше, вероятно, миллионы строк.

Подумайте, дал ли я вам такие инструкции:

Place your hands on your desk.
Tense your arm muscles.
Extend your knee and hip joints.
Relax your arms.
Move your arms backwards.
Move your left leg backwards.
Move your right leg backwards.
(continue for 10,000 more lines)

К тому времени, когда вы пройдете половину, или даже 5%, вы уже забыли, каковы были первые несколько шагов. Вы не могли бы определить большинство проблем, потому что вы не могли видеть лес за деревьями. Сравните с функциями:

stand_up();
walk_to(break_room);
pour(coffee);
walk_to(office);

Это, безусловно, гораздо более понятно, независимо от того, сколько комментариев вы можете поместить в построчную последовательную версию. Это также делает его гораздо более вероятно , вы заметите , что вы забыли сделать кофе, и , вероятно , забыли sit_down () в конце. Когда ваш разум размышляет о деталях регулярных выражений grep и awk, вы не можете придумать общую картину - «что делать, если не будет кофе»?

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

Конечно, есть и другие преимущества, которые обсуждаются в других ответах. Другое преимущество, которое не указано в других ответах, состоит в том, что функции обеспечивают гарантию, которая важна для предотвращения и исправления ошибок. Если вы обнаружите, что какая-то переменная $ foo в правильной функции walk_to () была неправильной, вы знаете, что вам нужно только взглянуть на остальные 6 строк этой функции, чтобы найти все, на что могла повлиять эта проблема, и все, что могло вызвало это быть неправильно. Без (правильных) функций, все и вся во всей системе может быть причиной некорректности $ foo, а $ foo может повлиять на все и вся. Поэтому вы не можете безопасно исправить $ foo без повторного изучения каждой строки программы. Если $ foo локально для функции,

Рэй Моррис
источник
1
Это не bashсинтаксис. Это позор, хотя; Я не думаю, что есть способ передать ввод таким функциям. (т.е. pour();< coffee). Это больше похоже на c++или php(я думаю).
голоса
2
@ tjt263 без скобок, это синтаксис bash: налить кофе. С паренсом это почти любой другой язык. :)
Рэй Моррис
6

Некоторые актуальные истины о программировании:

  • Ваша программа изменится, даже если ваш начальник настаивает, что это не так.
  • Только код и ввод влияют на поведение программы.
  • Называть сложно.

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

Тем не менее, у функций Bash есть некоторые проблемы, которых нет в большинстве языков:

  • Пространство имен ужасно в Bash. Например, если забыть использовать localключевое слово, это приведет к загрязнению глобального пространства имен.
  • Использование local foo="$(bar)"результатов в потере кода выходаbar .
  • Там нет именованных параметров, поэтому вы должны иметь в виду, что "$@"означает в разных контекстах.

* Прошу прощения, если это оскорбляет, но после использования комментариев в течение нескольких лет и разработки без них ** в течение нескольких лет становится ясно, что лучше.

** Использование комментариев для лицензирования, документации по API и т. П. Все еще необходимо.

l0b0
источник
Я поставил почти все локальные переменные, объявляя их нуль в начале функции ... local foo=""Тогда установив их с помощью выполнения команд , чтобы действовать на результат ... foo="$(bar)" || { echo "bar() failed"; return 1; }. Это быстро выводит нас из функции, когда требуемое значение не может быть установлено. Фигурные скобки необходимы, чтобы гарантировать, что return 1выполняется только при неудаче.
DocSalvager
6

Время - деньги

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

Я хочу сосредоточиться на одном ожидании: в рабочей среде «время - деньги» . Таким образом, отсутствие ошибок и производительность вашего кода оцениваются вместе с читабельностью , тестируемостью, ремонтопригодностью, рефакторируемостью, возможностью повторного использования ...

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

Более того, написание в независимых «модулях» кода (даже сценария bash) позволит вам работать «параллельно» с другим компонентом вашей команды, сокращая общее время производства и используя в лучшем случае опыт одного сингла, чтобы просматривать или переписывать часть с никаких побочных эффектов для других, чтобы переработать код, который вы только что написали "как есть"для другой программы / скрипта, для создания библиотек (или библиотек фрагментов), для уменьшения общего размера и связанной с этим вероятности ошибок, для отладки и тщательного тестирования каждой отдельной части ... и, конечно, она организует в логическом разделе вашу программу / скрипт и повысить его читабельность. Все вещи, которые сэкономят время и так деньги. Недостатком является то, что вы должны придерживаться стандартов и комментировать свои функции (что, тем не менее, вы должны делать в рабочей среде).

Соблюдение стандарта вначале замедлит вашу работу, но впоследствии ускорит работу всех остальных (и вас тоже). На самом деле, когда количество участников увеличивается, это становится неизбежной потребностью. Так, например, даже если я считаю, что глобальные переменные должны быть определены глобально, а не в функции, я могу понять стандарт, который инициализирует их в функции с именем declare_variables()всегда вызывается в первой строке main()одной ...

И последнее, но не менее важное: не стоит недооценивать возможность в современных редакторах исходного кода показывать или скрывать выборочно отдельные подпрограммы ( свертывание кода ). Это позволит сохранить компактность кода и сосредоточить внимание пользователя на экономии времени.

введите описание изображения здесь

Здесь выше вы можете увидеть, как разворачивается только walk_into_bar()функция. Даже другие были длиной в 1000 строк каждая, вы все равно могли держать под контролем весь код на одной странице. Обратите внимание, что он свернут даже в том разделе, куда вы идете, чтобы объявить / инициализировать переменные.

Hastur
источник
2

Помимо причин, приведенных в других ответах:

  1. Психология: у программиста, производительность которого измеряется строками кода, будет стимул писать излишне подробный код. Чем больше руководство сосредоточено на строках кода, тем больше у программиста стимулов расширять свой код с ненужной сложностью. Это нежелательно, так как повышенная сложность может привести к увеличению затрат на обслуживание и увеличению усилий, необходимых для исправления ошибок.
АРУ
источник
1
Это не такой плохой ответ, как говорят противники. Примечание: agc говорит, что это также возможно, и да, это так. Он не говорит, что это будет единственная возможность, и никого не обвиняет, только констатирует факты. Хотя я думаю, что сегодня почти невозможно услышать прямую контрактную работу в стиле «строка кода» -> «$$», косвенные средства довольно распространены, и да, масса производимого кода рассчитывается лидерами / боссами.
user259412
2

Другой причиной, которая часто упускается из виду, является синтаксический анализ bash:

set -eu

echo "this shouldn't run"
{
echo "this shouldn't run either"

Этот скрипт, очевидно, содержит синтаксическую ошибку, и bash вообще не должен его запускать, верно? Неправильно.

~ $ bash t1.sh
this shouldn't run
t1.sh: line 7: syntax error: unexpected end of file

Если мы обернем код в функцию, этого не произойдет:

set -eu

main() {
  echo "this shouldn't run"
  {
  echo "this shouldn't run either"
}

main
~ $ bash t1.sh
t1.sh: line 10: syntax error: unexpected end of file
Хьюберт Гжесковяк
источник