¿Por qué -a en "#! / Bin / sh -a" afecta a sed y "set -a" no?

20

Si ejecuto el siguiente archivo .sh:

#!/bin/sh -a
echo "a" | sed -e 's/[\d001-\d008]//g'

El resultado es un error:

sed: -e expresión # 1, char 18: Fin de rango inválido

Pero si ejecuto el siguiente archivo .sh:

#!/bin/sh
set -a
echo "a" | sed -e 's/[\d001-\d008]//g'

Se ejecuta sin error. ¿No se supone que el segundo código es equivalente al primero? ¿Por qué el error en el primero?

Rodrigo
fuente
No todos shson iguales. Ni todos los sed son equivalentes. Cual shestas usando ¿En qué sistema operativo? y ¿Qué sed (tal vez? sed --versionsi no falla)?
Isaac
1
configuración LC_COLLATE=C(o POSIX) para la llamada a sedsolucionar el problema
Jeff Schaller
44
Una diferencia que encontré: el primer script invoca sed (y presumiblemente cualquier otra utilidad) POSIXLY_CORRECT=yen el entorno, el segundo no tiene POSIXLY_CORRECTen el entorno. El shell desde el que invoco ambos scripts no tiene POSIXLY_CORRECTen su entorno.
Mark Plotnick
1
Ah, echo "a" | POSIXLY_CORRECT=y sed -e 's/[\d001-\d008]//g' reproduce tu problema
Isaac
1
Confirmar que lo anterior falla para mí exactamente como lo ha mostrado el OP en CentOS 7.x - GNU bash, versión 4.2.46 (2) -release (x86_64-redhat-linux-gnu) y CentOS Linux versión 7.5.1804 (Core) .
slm

Respuestas:

31

Cuando se llama a bash con el nombre sh, hace esto :

if (shell_name[0] == 's' && shell_name[1] == 'h' && shell_name[2] == '\0')
    act_like_sh++;

y luego establece la POSIXLY_CORRECTvariable de shell eny :

if (act_like_sh)
  {
    bind_variable ("POSIXLY_CORRECT", "y", 0);
    sv_strict_posix ("POSIXLY_CORRECT");
  }

bind_variablellamadas bind_variable_internal, que, si el atributo de shell aestá activado en ese momento (que sería si invocara el shell con -a), marca la variable de shell como exportada .

Entonces en tu primer guión:

#!/bin/sh -a
echo "a" | sed -e 's/[\d001-\d008]//g'

sedse invoca POSIXLY_CORRECT=yen su entorno, lo que hará que se queje [\d001-\d008]. (Lo mismo sucede si sed tiene la --posixopción).

En GNU sed, es un código de escape para el carácter cuyo valor numérico en base 10 es NNN , pero en modo POSIX, esto es deshabilitado dentro de una expresión entre corchetes, por lo que , literalmente significa los caracteres , etc., siendo el rango de a . En orden de códigos de caracteres, viene antes (y el rango incluye todos los dígitos excepto cero, más todas las letras mayúsculas, más algunos caracteres especiales). Sin embargo, en la configuración regional que estaba utilizando, se ordena antes , por lo que el rango no es válido.\dNNN[\d001-\d008]\d1\1\en_US.UTF-8\1

En tu segundo guión:

#!/bin/sh
set -a
echo "a" | sed -e 's/[\d001-\d008]//g'

aunque POSIXLY_CORRECTestá configurado en el shell, no se exporta, por lo que sed se invoca sin POSIXLY_CORRECTen el entorno y sed se ejecuta con extensiones GNU.

Si agrega export POSIXLY_CORRECTcerca de la parte superior de su segundo script, también verá quejarse.

Mark Plotnick
fuente
66
Para mí, eso es un error.
Stéphane Chazelas
1
¡Santo horror, Batman! Esa es una peculiaridad interesante (y un poco de un cambio de ver un problema que viene de la /bin/shrealidad siendo Bash). Lo mismo sucede si POSIXLY_CORRECTestá en el entorno antes de que comience el shBash: también lo transmitirá como POSIXLY_CORRECT=y.
ilkkachu
3
@StevenPenny, pero POSIXLY_CORRECT no está en el entorno cuando se inicia el shell y el script no lo configura. La cáscara lo hace. Crea una variable de entorno de la nada, lo cual es muy malo ya que lo hace en un modo donde se supone que debe estar, e intenta cumplir con los estándares.
ilkkachu
44
FWIW, Bash tampoco parece documentar que establecería POSIXLY_CORRECT por sí solo. No se menciona en la lista de efectos del modo POSIX y la descripción de la variable solo dice que configurarlo cambia el shell al modo POSIX, no al revés.
ilkkachu
1
@ilkkachu. Hecho. Creo que la especificación POSIX también debe actualizarse para aclarar qué variables se ven afectadas allexport.
Stéphane Chazelas