Dlaczego -a w „#! / Bin / sh -a” wpływa na sed, a „set -a” nie?

20

Jeśli uruchomię następujący plik .sh:

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

Rezultatem jest błąd:

sed: -e wyrażenie # 1, char 18: Niepoprawny koniec zakresu

Ale jeśli uruchomię następujący plik .sh:

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

Działa bez błędów. Czy drugi kod nie powinien być równoważny z pierwszym? Dlaczego błąd w pierwszym?

Rodrigo
źródło
Nie wszystkie shsą takie same. Ani wszystkie sed nie są równoważne. Których shużywasz? W jakim systemie operacyjnym? i Który sed (może? sed --versionjeśli to nie zawiedzie)?
Izaak
1
ustawienie LC_COLLATE=C(lub POSIX) połączenia w celu sedobejścia problemu
Jeff Schaller
4
Jedną różnicę, którą znalazłem: pierwszy skrypt wywołuje sed (i przypuszczalnie dowolne inne narzędzie) POSIXLY_CORRECT=yw środowisku, a drugi nie ma go POSIXLY_CORRECTw środowisku. Powłoka, z której wywołuję oba skrypty, nie ma POSIXLY_CORRECTw swoim środowisku.
Mark Plotnick,
1
Ach, echo "a" | POSIXLY_CORRECT=y sed -e 's/[\d001-\d008]//g' odtwórz swój problem
Izaak,
1
Potwierdzenie, że powyższe nie powiedzie się dla mnie dokładnie tak, jak OP pokazane w CentOS 7.x - GNU bash, wersja 4.2.46 (2) -release (x86_64-redhat-linux-gnu) i CentOS Linux wydanie 7.5.1804 (Core) .
slm

Odpowiedzi:

31

Kiedy bash jest wywoływany z nazwą sh, robi to :

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

a następnie ustawia POSIXLY_CORRECTzmienną powłoki nay :

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

bind_variablewywołań bind_variable_internal, które, jeśli atrybut powłoki ajest w tym czasie włączony (tak jak byłoby w przypadku wywołania powłoki -a), oznaczają zmienną powłoki jako wyeksportowaną .

Więc w twoim pierwszym skrypcie:

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

sedjest wywoływane POSIXLY_CORRECT=yw jego środowisku, co spowoduje, że narzeka [\d001-\d008]. (To samo dzieje się, jeśli podano --posixopcję sed .)

W GNU sed, jest kodem ucieczki dla znaku, którego wartością liczbową w bazie-10 jest NNN , ale w trybie POSIX jest on wyłączony w wyrażeniu nawiasowym, więc\dNNN[\d001-\d008] , dosłownie oznacza postacie \, ditp, przy czym zakres wynosi od 1do \. W kolejności kodów znaków 1występuje przed \(a zakres obejmuje wszystkie cyfry oprócz zera, plus wszystkie duże litery oraz niektóre znaki specjalne). Jednak w en_US.UTF-8ustawieniach regionalnych, których używasz, \sortuje się wcześniej 1, więc zakres jest nieprawidłowy.

W twoim drugim skrypcie:

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

nawet jeśli POSIXLY_CORRECTjest ustawiony w powłoce, nie jest eksportowany, więc sed jest wywoływany bez POSIXLY_CORRECTw środowisku, a sed działa z rozszerzeniami GNU.

Jeśli dodasz export POSIXLY_CORRECT w górnej części drugiego skryptu, zobaczysz również, że narzeka.

Mark Plotnick
źródło
6
Dla mnie to błąd.
Stéphane Chazelas,
1
święty horror, Batman! To ciekawe dziwactwo (i trochę zmian, aby zobaczyć problem, który pochodzi z /bin/shfaktycznie jest bash). To samo dzieje się, jeśli POSIXLY_CORRECTjest w środowisku przed rozpoczęciem shBash: przekaże go również jako POSIXLY_CORRECT=y.
ilkkachu
3
@StevenPenny, ale POSIXLY_CORRECT nie ma go w środowisku, gdy uruchamia się powłoka, a skrypt go nie ustawia. Powłoka działa. Tworzy zmienną środowiskową znikąd, co jest szczególnie złe, ponieważ robi to w trybie, w którym powinna być, i stara się być zgodna ze standardami.
ilkkachu
4
FWIW, Bash również nie wydaje się dokumentować, że sam by to ustawił POSIXLY_CORRECT. Nie ma o tym wzmianki na liście efektów trybu POSIX, a opis zmiennej mówi tylko, że ustawienie go zmienia powłokę w tryb POSIX, a nie na odwrót.
ilkkachu
1
@ilkkachu. Gotowy. Myślę, że specyfikacja POSIX powinna również zostać zaktualizowana, aby wyjaśnić, na które zmienne ma wpływ allexport.
Stéphane Chazelas