Pourquoi -a dans «#! / Bin / sh -a» affecte sed et «set -a» ne fonctionne pas?

20

Si j'exécute le fichier .sh suivant:

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

Le résultat est une erreur:

sed: -e expression # 1, caractère 18: fin de plage non valide

Mais si j'exécute le fichier .sh suivant:

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

Il s'exécute sans erreur. Le deuxième code n'est-il pas censé être équivalent au premier? Pourquoi l'erreur dans la première?

Rodrigo
la source
Tous ne shsont pas pareils. Tous les sed ne sont pas équivalents non plus. Lequel shutilisez-vous? Dans quel OS? et quel sed (peut-être? sed --versionsi ça ne manque pas)?
Isaac
1
définition LC_COLLATE=C(ou POSIX) de l'appel pour sedcontourner le problème
Jeff Schaller
4
Une différence que j'ai trouvée: le premier script invoque sed (et probablement tout autre utilitaire) avec POSIXLY_CORRECT=ydans l'environnement, le second n'en a pas POSIXLY_CORRECTdans l'environnement. Le shell à partir duquel j'appelle les deux scripts n'a pas POSIXLY_CORRECTdans son environnement.
Mark Plotnick
1
Ah, echo "a" | POSIXLY_CORRECT=y sed -e 's/[\d001-\d008]//g' reproduisez votre problème
Isaac
1
Confirmer que ce qui précède échoue pour moi exactement comme l'OP l'a montré sur CentOS 7.x - GNU bash, version 4.2.46 (2) -release (x86_64-redhat-linux-gnu) et CentOS Linux version 7.5.1804 (Core) .
slm

Réponses:

31

Lorsque bash est appelé avec le nom sh, il fait ceci :

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

puis définitPOSIXLY_CORRECTy plus tard la variable shell sur :

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

bind_variableappels bind_variable_internal, qui, si l'attribut shell aest activé à ce moment (ce qui serait le cas si vous appeliez le shell -a), marque la variable shell comme exportée .

Donc dans votre premier script:

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

sedest invoqué avec POSIXLY_CORRECT=ydans son environnement, ce qui le fera se plaindre [\d001-\d008]. (La même chose se produit si sed a la --posixpossibilité.)

Dans GNU sed, est un code d'échappement pour le caractère dont la valeur numérique de base 10 est NNN , mais en mode POSIX, cette option est désactivée dans une expression de support, donc , signifie littéralement les personnages , etc., la gamme étant de à . Dans l'ordre des codes de caractères, vient avant (et la plage comprend tous les chiffres sauf zéro, plus toutes les lettres majuscules, plus quelques caractères spéciaux). Dans les paramètres régionaux que vous utilisiez, les tris avant , cependant, de sorte que la plage n'est pas valide.\dNNN[\d001-\d008]\d1\1\en_US.UTF-8\1

Dans votre deuxième script:

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

même s'il POSIXLY_CORRECTest défini dans le shell, il n'est pas exporté, donc sed est invoqué sans POSIXLY_CORRECTdans l'environnement, et sed s'exécute avec des extensions GNU.

Si vous ajoutez en export POSIXLY_CORRECThaut de votre deuxième script, vous verrez également sed se plaindre.

Mark Plotnick
la source
6
Pour moi, c'est un bug.
Stéphane Chazelas
1
horreur de la coquille sacrée, Batman! C'est une bizarrerie intéressante (et un peu de changement pour voir un problème qui vient du /bin/shfait d' être Bash). La même chose se produit si se POSIXLY_CORRECTtrouve dans l'environnement avant le shdémarrage de Bash: il le transmettra également en tant que POSIXLY_CORRECT=y.
ilkkachu
3
@StevenPenny, mais POSIXLY_CORRECT n'est pas dans l'environnement au démarrage du shell et le script ne le définit pas. La coquille fait. Il crée une variable d'environnement de nulle part, ce qui est extrêmement mauvais car il le fait dans un mode où il est censé être, et essaie d'être conforme aux normes.
ilkkachu
4
FWIW, Bash ne semble pas non plus documenter qu'il se définirait POSIXLY_CORRECTde lui-même. Il n'y en a aucune mention dans la liste des effets du mode POSIX et la description de la variable dit seulement que le paramétrer fait passer le shell en mode POSIX, et non l'inverse.
ilkkachu
1
@ilkkachu. Terminé. Je pense que la spécification POSIX devrait également être mise à jour pour clarifier les variables affectées allexport.
Stéphane Chazelas