При написании скриптов bash, как вы знаете, можно использовать круглые () и фигурные скобки {}. И те, и другие позволяют объединить несколько операторов в один составной. Давайте рассмотрим, в чем же различие скобок в bash, и когда имеет смысл использовать в скриптах круглые скобки, а когда фигурные.
Сходства
И те, и другие скобки позволяют объединять несколько команд в один составной оператор, который может получать какие-то данные на вход и выдавать какие-то данные на выход. Для перенаправления данных обычно традиционно используют пайп (вертикальную черту). Выглядит это так:
command1 | ( command2 ... commandN ) | command M
Выполняется первая команда, которая передает свой стандартный поток вывода составному оператору, обозначенному скобками. Обычно встречается именно такой вариант — с круглыми скобками.
Фигурные скобки более привычно наблюдать при создании функций bash:
function(){ command1 ... commandN }
И в первом, и во втором случае скобки объединяют группы операторов. И работают они, в принципе, похоже. Поэтому никто нам не запрещает создать такую структуру:
command1 | { command2 ... commandN } | commandM
Работает она похожим образом. Несколько операторов, на вход принимается вывод команды command1, а вывод перенаправляется на поток стандартного ввода commandM.
Различия
Чтобы понять различия давайте посмотрим два варианта скрипта. Первый вариант:
VAR1="/var" ls | ( echo $VAR1 ) | sort
Второй вариант:
VAR1="/var" ls | { echo $VAR1 } | sort
Вроде бы одинаковые скрипты. В чем, казалось бы, разница? Давайте посмотрим на результат выполнения. Результат одинаковый. Значит, можно использовать и тот, и другой скрипт абсолютно одинаково?
Немного поменяем скрипты.
Первый вариант:
#!/bin/bash for i in {1..10000} do ls | ( ls / > /dev/null ) done
Второй вариант:
#!/bin/bash for i in {1..10000} do ls | { ls / > /dev/null } done
Замерим время выполнения этих скриптов
$ time ./script1.sh real 0m28.021s user 0m1.187s sys 0m5.863s $ time ./script2.sh real 0m33.163s user 0m0.787s sys 0m4.517s
Наглядно видно различие во времени выполнения, если несколько раз запустить скрипты, показатели будут примерно такие же. Причем абсолютное время выполнения скрипта с круглыми скобками меньше, а нагрузка на систему больше. Скрипт с фигурным скобками работает медленнее, зато меньше нагружает систему. Команда, которую мы использовали, — встроенная команда bash
Теперь посмотрим вывод другой команды time — внешней.
$ /usr/bin/time ./script1.sh 1.17user 5.78system 0:27.55elapsed 25%CPU (0avgtext+0avgdata 3168maxresident)k 0inputs+0outputs (0major+8557180minor)pagefaults 0swaps $ /usr/bin/time ./script2.sh 0.71user 4.60system 0:32.66elapsed 16%CPU (0avgtext+0avgdata 3168maxresident)k 0inputs+0outputs (0major+9954334minor)pagefaults 0swaps
Явно видна разница в потреблении процессорного времени. Давайте посчитаем разницу в процентах по времени и по потреблению процессора.
Отношение времени работы скриптов:
32,66/27,55=1,18548094374
Таким образом, вариант с фигурными скобками работает на 18,5 процентов медленнее.
Давайте теперь посмотрим, какова разница в потреблении процессорного времени:
0,25/0,16=1,5625
Вариант с фигурными скобками использует на 56,2 процента процессорного времени меньше.
Почему так происходит? Ответ можно найти в документации по bash. То, что находится между круглыми скобками, выполняется в отдельном подпроцессе. А то, что находится между фигурными скобками — выполняется в контексте текущей оболочки.