Por que -a em "#! / Bin / sh -a" afeta sed e "set -a" não?

20

Se eu executar o seguinte arquivo .sh:

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

O resultado é um erro:

expressão sed: -e # 1, caractere 18: final do intervalo inválido

Mas se eu executar o seguinte arquivo .sh:

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

É executado sem erros. O segundo código não deveria ser equivalente ao primeiro? Por que o erro no primeiro?

Rodrigo
fonte
Nem todos shsão iguais. Nem todos os sed são equivalentes. Qual shvocê está usando? Em qual SO? e Qual sed (talvez? sed --versionse não falhar)?
Isaac
11
configuração LC_COLLATE=C(ou POSIX) para a chamada para sedtrabalhos em torno da questão
Jeff Schaller
4
Uma diferença que encontrei: o primeiro script invoca sed (e presumivelmente qualquer outro utilitário) POSIXLY_CORRECT=yno ambiente, o segundo não possui POSIXLY_CORRECTno ambiente. O shell do qual invoco os dois scripts não possui POSIXLY_CORRECTem seu ambiente.
precisa saber é o seguinte
11
Ah, echo "a" | POSIXLY_CORRECT=y sed -e 's/[\d001-\d008]//g' reproduza seu problema
Isaac
11
Confirmando que o acima falhou para mim exatamente como o OP mostrou no CentOS 7.x - GNU bash, versão 4.2.46 (2) - release (x86_64-redhat-linux-gnu) e no CentOS Linux versão 7.5.1804 (Core) .
slm

Respostas:

31

Quando o bash é chamado com o nome sh, ele faz o seguinte :

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

e depois define a POSIXLY_CORRECTvariável do shell comoy :

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

bind_variablechama bind_variable_internal, que, se o atributo shell aestiver ativado no momento (o que seria se você invocasse o shell -a), marca a variável do shell como exportada .

Então, no seu primeiro script:

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

sedé invocado POSIXLY_CORRECT=yem seu ambiente, o que fará com que ele se queixe [\d001-\d008]. (O mesmo acontece se sed tiver a --posixopção.)

Em GNU sed, é um código de escape para o carácter cujo valor numérico na base 10 é NNN , mas no modo POSIX, este é desactivado dentro de um suporte de expressão, assim , meios literalmente os caracteres , etc., com o intervalo sendo desde para . Na ordem dos códigos de caracteres, vem antes (e o intervalo inclui todos os dígitos, exceto zero, além de todas as letras maiúsculas e alguns caracteres especiais). No local que você estava usando, classifica antes , no entanto, portanto, o intervalo é inválido.\dNNN[\d001-\d008]\d1\1\en_US.UTF-8\1

No seu segundo script:

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

mesmo estando POSIXLY_CORRECTdefinido no shell, ele não é exportado, portanto, o sed é invocado sem POSIXLY_CORRECTo ambiente e o sed é executado com extensões GNU.

Se você adicionar export POSIXLY_CORRECTperto da parte superior do seu segundo script, também verá sed recla.

Mark Plotnick
fonte
6
Para mim, isso é um bug.
Stéphane Chazelas 13/08/18
11
horror sagrado, Batman! Essa é uma peculiaridade interessante (e um pouco de uma mudança para ver um problema que vem de /bin/shrealmente estar Bash). O mesmo acontece se POSIXLY_CORRECTestiver no ambiente antes do shBash começar: ele também passará como POSIXLY_CORRECT=y.
Ilkkachu
3
@StevenPenny, mas POSIXLY_CORRECT não está no ambiente quando o shell é iniciado e o script não o define. A concha faz. Ele cria uma variável de ambiente do nada, o que é muito ruim, pois faz isso em um modo em que deveria estar e tenta ser compatível com os padrões.
ilkkachu
4
FWIW, o Bash também não parece documentar que definiria POSIXLY_CORRECTpor conta própria. Não há menção a isso na lista de efeitos do modo POSIX, e a descrição da variável diz apenas que a configuração altera o shell para o modo POSIX, e não o contrário.
Ilkkachu
11
@ilkkachu. Feito. Eu acho que a especificação POSIX também deve ser atualizada para esclarecer quais variáveis ​​são afetadas allexport.
Stéphane Chazelas