¿Cuándo usar () vs. {} en bash?

74

Estoy estudiando scripts de shell con bash y necesito saber la diferencia entre (...)y {...}. ¿Cómo se selecciona entre los dos al escribir un guión?

Mente gorda
fuente
1
Ver wiki.bash-hackers.org
Helio
3
¿Se refería solo al contexto de la agrupación de comandos?
heemayl

Respuestas:

87

Si desea que los efectos secundarios de la lista de comandos afecten a su shell actual , use {...}
Si desea descartar cualquier efecto secundario, use(...)

Por ejemplo, podría usar una subshell si:

  • quiero modificar $IFSalgunos comandos, pero no quiero modificar $IFSglobalmente el shell actual
  • cden algún lugar, pero no quiero cambiar el $PWDpara el shell actual

Vale la pena señalar que los paréntesis se pueden usar en una definición de función:

  • uso normal: llaves: el cuerpo de la función se ejecuta en el shell actual; los efectos secundarios permanecen después de que se completa la función

    $ count_tmp() { cd /tmp; files=(*); echo "${#files[@]}"; }
    $ pwd; count_tmp; pwd
    /home/jackman
    11
    /tmp
    $ echo "${#files[@]}"
    11    
  • uso inusual: paréntesis: el cuerpo de la función se ejecuta en una subshell; los efectos secundarios desaparecen cuando sale la subshell

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

Documentación

Glenn Jackman
fuente
11
Después de muchos años de desarrollo de shell, no sabía que podía usar paréntesis para ejecutar funciones en subshells. ¡Qué gran idea para evitar contaminar el espacio de nombres global!
l0b0
77
El uso de la localpalabra clave ayuda mucho a limpiar esa contaminación.
Glenn Jackman
2
Sí, pero debes recordar declarar cada variable local, y desordena el código.
l0b0
44
Sugerencia: si desea funciones sin efectos secundarios pero evita la sintaxis de declaración de función inusual (de la cual los editores de código pueden no estar al tanto), simplemente use paréntesis en la llamada de función en lugar de la declaración:pwd; (count_tmp); pwd;
Juve
2
al shell ... foo () (:;) es equivalente a foo () {(:;); } ¡Así es como lo informa si lo preguntas!
Anthony
23

De la documentación oficial de bash :

()

( list )

Al colocar una lista de comandos entre paréntesis, se crea un entorno de subshell y cada uno de los comandos de la lista se ejecuta en esa subshell. Dado que la lista se ejecuta en una subshell, las asignaciones de variables no permanecen vigentes una vez que se completa la subshell.

{}

{ list; }

Colocar una lista de comandos entre llaves hace que la lista se ejecute en el contexto actual del shell. No se crea ninguna subshell. Se requiere la siguiente lista de punto y coma (o nueva línea).

Trauma digital
fuente
9

El código en '{}' se ejecuta en el subproceso / proceso / entorno actual y se conservan los cambios, para decirlo de manera más sucinta, el código se ejecuta en el ámbito actual.
El código en '()' se ejecuta dentro de un proceso secundario separado de bash que se descarta después de la ejecución. Este proceso secundario a menudo se conoce como un subconjunto y se puede considerar como un nuevo ámbito secundario.

Como ejemplo, considere lo siguiente ...

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

 ~ # 

Observe que en el primer ejemplo con '{}' la variable aún se establece incluso después del cierre '}', mientras que en el ejemplo con '()' la variable no se establece fuera del alcance de '()'.

fuma2345
fuente
4

(...)se utilizan para ejecutar código en un sub-shell. El código usado entre bewteen {...}no se usará en un sub-shell.

Antoine Orsoni
fuente