Configurar opciones de bash en un comando compuesto

Configurar opciones de bash en un comando compuesto

Descubrí que configurar la extglobopción Shell solo dentro de un compuesto produce fallas en los globos extendidos posteriores. ¿Es necesario configurar las opciones de Shell fuera de los comandos compuestos? No vi ninguna indicación de tal requisito en las páginas de manual de Bash.

Como ejemplo, el siguiente script funciona bien (se imprime a.0 a.1):

#!/bin/bash
touch a.0   a.1 \
      a.b.0 a.b.1
shopt -s extglob
ls "a."!(b*)

Sin embargo, si las dos últimas líneas se ejecutan como un comando compuesto, el script falla con el siguiente error:

syntax error near unexpected token `('
`    ls "a."!(b*)'

Esto se probó utilizando las versiones de Bash de 4.2 a 4.4 y con una variedad decomandos compuestos:

(1) condicional --if

#!/bin/bash
touch a.0   a.1 \
      a.b.0 a.b.1
if true; then
    shopt -s extglob
    ls "a."!(b*)
fi

(2) tirantes -{ }

#!/bin/bash
touch a.0   a.1 \
      a.b.0 a.b.1
{
    shopt -s extglob
    ls "a."!(b*)
}

(3) subcapa -- ( ):

#!/bin/bash
touch a.0   a.1 \
      a.b.0 a.b.1
(
    shopt -s extglob
    ls "a."!(b*)
)

En todos los casos, si shoptse mueve fuera del comando compuesto, el script se ejecuta correctamente.

Respuesta1

Ninguna parte de un comando compuesto se ejecuta antes de que se analice todo el comando, lo cual está documentado indirectamente en elOperación Shellsección del manual: toda la tokenización y el análisis se realizan antes de que se ejecute "el" comando. Al habilitarlo, extglobse cambia la sintaxis del idioma al agregar nuevos operadores de coincidencia de patrones, que se reconocen durante la tokenización.

Debido a que el shoptcomando no se ha ejecutado en el momento en !(que se alcanza, se ve como un intento de expansión del historial ( !) o el operador de control (, en lugar de !(verse como un solo elemento (y lo mismo para @(, etc., excepto que no hay ninguna expansión del historial). allá).

Cuando el análisis llega a ese token, cualquiera de los casos generalmente será un error, aunque !(...)al comienzo de una línea o después timehay una tubería de subcapa negada. " unexpected token `('" significa que no pudo aceptar una expresión de subcapa en ese lugar.

Esto es algo molesto cuando desea habilitar extglob solo temporalmente en un subshell. Una solución alternativa es definir una función que utilice el glob que desea, luego volver a deshabilitar extglob yentoncesllame a la función desde el subshell con extglob habilitado:

shopt -s extglob
f() { ls "a."!(b*) ; }
shopt -u extglob
(
    shopt -s extglob
    f
)

Es muy torpe.


El mismo efecto ocurre si crea un alias dentro de un comando compuesto, porque también se procesan antes del análisis:

if true
then
    alias foo=echo
    foo bar
fi
foo xyz

se imprimirá foo: command not found, y luego xyz, porque el aliasescreado, pero no estará disponible hasta que ifesté terminado.

información relacionada