Что на самом деле делает оператор диапазона в «sed», он сломан в GNU / busybox? - PullRequest
1 голос
/ 27 марта 2019

Интересно, могут ли реализации «sed» в GNU и BusyBox быть сломаны?

Моя реализация sed по умолчанию - из GNU.

POSIX говорит:

Команда редактирования с двумя адресами должна выбрать включающий диапазон из первого пространства шаблона, которое соответствует первому адресу, через следующее пространство шаблона, которое соответствует второму.

Но тогда почему задается

$ { echo ha; echo ha; echo ha; } | sed '0,/ha/ !d'
ha

вместо

ha
ha

?Очевидно, что второе «ха» здесь - это следующее «шаблонное» пространство, которое совпадает, поэтому оно также должно быть выведено!

Но, что еще более странно,

$ { echo ha; echo ha; echo ha; } | busybox sed '0,/ha/ !d'

ничего не выводит приall!

Но даже если sed будет делать то, что говорит определение POSIX, все еще неясно, что должно произойти, когда выражение диапазона фактически проверяется.

Имеет ли каждое условие диапазона свое внутреннее условие?государство?Или существует единственное глобальное состояние для всех условий диапазона в сценарии sed?

Очевидно, что условие диапазона должно по крайней мере помнить, находится ли оно в данный момент в «поиске совпадения первого адреса» -состояние или в «поиск совпадения второго адреса» -состояния.Возможно, ему даже нужно запомнить третье состояние: «Я уже обработал диапазон и больше не буду совпадать, несмотря ни на что».

Конечно, имеет значение, когда обновляются эти условия: каждый раз, когда читается новое пространство шаблона?Каждый раз, когда пространство шаблона изменяется, скажем, с помощью s-команды?Или просто, если поток управления достигает условия диапазона?

Итак, что это?

Пока я не узнаю лучше, я буду избегать условий диапазона в моих sed-скриптах и ​​буду считать ихсомнительная особенность.

1 Ответ

3 голосов
/ 27 марта 2019

Два ответа:

  1. 0 не является действительным адресом POSIX (количество строк от 1)
  2. 0,/re/ является расширением GNU

Справочная страница GNU awk включает в себя:

0, addr2

Начинайте в состоянии «совпадающий первый адрес», пока addr2 не станет найденный. Это похоже на 1, addr2, за исключением того, что если addr2 совпадает самая первая строка ввода 0, форма addr2 будет в конце его диапазона, тогда как форма 1, addr2 по-прежнему будет на начало его ассортимента. Это работает только тогда, когда addr2 является обычным выражение.

Возможно, это поможет уточнить:

$ { echo ha1; echo ha2; echo ha3; } | sed '0,/ha/ !d'
ha1

$ { echo ha1; echo ha2; echo ha3; } | sed '1,/ha/ !d'
ha1
ha2

$ { echo ha1; echo ha2; echo ha3; } | sed --posix '0,/ha/ !d'
sed: -e expression #1, char 8: invalid usage of line address 0

Код busybox явно проверяет, что addr1 больше 0 и поэтому никогда не входит в соответствующее состояние. См. исходный код busybox, строка 1121 :

            || (sed_cmd->beg_line > 0

  1. Каждый матч поддерживает свое собственное состояние, так как несколько могут быть активны одновременно.

POSIX говорит:

Команда редактирования с двумя адресами должна выбрать включающий диапазон из первого пространства шаблона, которое соответствует первому адресу, через следующее пространство шаблона, которое соответствует второму. (Если второй адрес является номером, который меньше или равен первому выбранному номеру строки, должна быть выбрана только одна строка.) Начиная с первой строки, следующей за выбранным диапазоном, sed будет снова искать первый адрес. После этого процесс повторяется.

Тест проводится каждый раз, когда он встречается:

$ { echo ..a; echo ..b; echo ..c; } |\
  sed -n '
             =;
             y/cba/ba:/;
     1 ,/b/  s/$/ 1/p;
    /a/,/c/  s/$/ 2/p;
     2,  3   s/$/ 3/p;
  '
1
..: 1
2
..a 1
..a 1 2
..a 1 2 3
3
..b 1
..b 1 2
..b 1 2 3

Это также демонстрируется, например, исходным кодом busybox - см. Определение типа sed_cmd_s.

...