Чому -a в "#! / Bin / sh -a" впливає на sed, а "set -a" не робить?


20

Якщо я запускаю такий .sh файл:

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

Результатом є помилка:

sed: -e вираз №1, графі 18: Недійсний кінець діапазону

Але якщо я запускаю такий .sh-файл:

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

Він працює без помилок. Хіба другий код не повинен бути еквівалентним першому? Чому помилка в першій?


Не всі shоднакові. Не всі sed є рівнозначними. Що shви використовуєте? У якій ОС? і Який сід (можливо? sed --versionякщо він не виходить з ладу)?
Ісаак

1
налаштування LC_COLLATE=C(або POSIX) для заклику до sedвирішення проблеми
Джефф Шаллер

4
Я знайшов одну різницю: перший скрипт викликає sed (і, мабуть, будь-яку іншу утиліту) POSIXLY_CORRECT=yу середовищі, другий не має POSIXLY_CORRECTсередовища. Оболонки, з якої я викликаю обидва сценарії, POSIXLY_CORRECTу її середовищі немає.
Марк Плотнік

1
Ах, echo "a" | POSIXLY_CORRECT=y sed -e 's/[\d001-\d008]//g' відтворіть свою проблему
Ісаак

1
Підтвердження того, що вищезгадане для мене не вдається точно так, як показала ОП у CentOS 7.x - GNU bash, версія 4.2.46 (2) -випуск (x86_64-redhat-linux-gnu) та випуск CentOS Linux 7.5.1804 (Core) .
slm

Відповіді:


31

Коли bash викликається з ім'ям sh, він робить це :

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

а потім встановлює POSIXLY_CORRECTзмінну оболонки наy :

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

bind_variableвиклики bind_variable_internal, які, якщо атрибут оболонки aввімкнено (що було б, якщо ви посилаєтесь на оболонку -a), позначає змінну оболонки як експортовану .

Отже, у першому сценарії:

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

sedвикликає POSIXLY_CORRECT=yу своєму оточенні, що змусить її скаржитися [\d001-\d008]. (Те саме відбувається, якщо sed надається --posixопція.)

У ГНУ СЕД, є кодом виходу для символу якого чисельне значення в базі-10 NNN , але в режимі POSIX, це відключено всередині виразу кронштейна, так що , буквально означає символи , і т.д., при цьому діапазон від до . У порядку символьних кодів виходить раніше (а діапазон включає всі цифри, крім нуля, плюс всі великі літери плюс деякі спеціальні символи). У локальній частині, яку ви використовували, сортуйте раніше , але діапазон недійсний.\dNNN[\d001-\d008]\d1\1\en_US.UTF-8\1

У вашому другому сценарії:

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

незважаючи на те POSIXLY_CORRECT, що встановлено в оболонці, він не експортується, тому sed викликається без POSIXLY_CORRECTсередовища, а sed працює з розширеннями GNU.

Якщо ви додасте export POSIXLY_CORRECTбіля верхньої частини другого сценарію, ви також побачите sed скарги.


6
Для мене це помилка.
Стефан Шазелас

1
святий жах снарядів, Бетмен! Це цікава особливість (і трохи змін , щоб побачити проблему , яка виходить з /bin/shфактично є Bash). Те саме відбувається, якщо POSIXLY_CORRECTзнаходиться в оточенні до shзапуску Bash: він також передасть його як POSIXLY_CORRECT=y.
ilkkachu

3
@StevenPenny, але POSIXLY_CORRECT він не знаходиться в середовищі, коли оболонка запускається, і сценарій не встановлює її. Оболонка робить. Це створює змінну середовища з нізвідки, що дуже погано, оскільки це робиться в режимі, де це повинно бути, і намагається бути стандартним.
ilkkachu

4
FWIW, схоже, Bash також не підтверджує, що встановив би це POSIXLY_CORRECTсамостійно. У списку ефектів режиму POSIX про це не згадується, і опис змінної говорить лише про те, що встановлення зміни оболонки переходить у режим POSIX, а не навпаки.
ilkkachu

1
@ilkkachu. Зроблено. Я думаю, що специфікацію POSIX слід також оновити, щоб уточнити, на які змінні впливає allexport.
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.