Когда использовать () против {} в bash?

74

Я изучаю сценарии оболочки с bash, и мне нужно знать разницу между (...)и {...}. Как выбрать между двумя при написании сценария?

Жирный разум
источник
1
Смотрите wiki.bash-hackers.org
Helio
3
Вы имели ввиду только в контексте группировки команд?
Heemayl

Ответы:

87

Если вы хотите, чтобы побочные эффекты из списка команд влияли на вашу текущую оболочку, используйте {...}
Если вы хотите отменить любые побочные эффекты, используйте(...)

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

  • хочу изменить $IFSнесколько команд, но я не хочу изменять $IFSглобально для текущей оболочки
  • cdгде-то, но я не хочу менять $PWDтекущую оболочку

Стоит отметить, что круглые скобки могут использоваться в определении функции:

  • обычное использование: фигурные скобки: тело функции выполняется в текущей оболочке; побочные эффекты остаются после завершения функции

    $ count_tmp() { cd /tmp; files=(*); echo "${#files[@]}"; }
    $ pwd; count_tmp; pwd
    /home/jackman
    11
    /tmp
    $ echo "${#files[@]}"
    11    
    
  • необычное использование: круглые скобки: тело функции выполняется в подоболочке; побочные эффекты исчезают при выходе из подоболочки

    $ cd ; unset files
    $ count_tmp() (cd /tmp; files=(*); echo "${#files[@]}")
    $ pwd; count_tmp; pwd
    /home/jackman
    11
    /home/jackman
    $ echo "${#files[@]}"
    0
    

Документация

Гленн Джекман
источник
11
После многих лет разработки оболочки я не знал, что вы можете использовать скобки для запуска функций в подоболочках. Какая отличная идея, чтобы не загрязнять глобальное пространство имен!
10
7
Использование localключевого слова имеет большое значение для очистки этого загрязнения.
Гленн Джекман
2
Да, но вы должны помнить, чтобы объявить каждую переменную локальной, и это загромождает код.
10
4
Подсказка: если вы хотите использовать функции без побочных эффектов, но избегаете необычного синтаксиса объявления функций (о котором редакторы кода могут не знать), тогда просто используйте скобки в вызове функции, а не в объявлении:pwd; (count_tmp); pwd;
Juve
2
оболочке ... foo () (:;) эквивалентно foo () {(:;); } Вот как он сообщает об этом, если вы спросите!
Энтони
23

Из официальной документации bash :

()

( list )

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

{}

{ list; }

Помещение списка команд в фигурные скобки приводит к тому, что список выполняется в текущем контексте оболочки. Никакая подоболочка не создана. Точка с запятой (или новая строка) следующий список обязателен.

Цифровая травма
источник
9

Код в «{}» выполняется в текущем потоке / процессе / среде, и изменения сохраняются, если говорить более кратко, код выполняется в текущей области.
Код в '()' запускается внутри отдельного дочернего процесса bash, который сбрасывается после выполнения. Этот дочерний процесс часто называют вложенной оболочкой, и его можно рассматривать как новую дочернюю область.

В качестве примера рассмотрим следующее ...

 ~ # { test_var=test }
 ~ # echo $test_var
 test
 ~ # ( test_var2=test2 )
 ~ # echo $test_var2

 ~ # 

Обратите внимание, что в первом примере с «{}» переменная по-прежнему установлена ​​даже после закрывающего «}», тогда как в примере с «()» переменная не установлена ​​вне области действия «()».

smokes2345
источник
4

(...)используются для запуска кода в под-оболочке. Код, используемый ниже {...}, не будет использоваться в под-оболочке.

Антуан Орсони
источник