Что на самом деле делает оператор диапазона в "sed", он сломан в GNU/busybox?
Интересно, могут ли реализации "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'
вообще ничего не выводит!
Но даже если sed будет делать то, что говорит определение POSIX, все еще неясно, что должно произойти, когда выражение диапазона фактически проверяется.
Каждое ли условие диапазона имеет свое внутреннее состояние? Или в сценарии sed есть единое глобальное состояние для всех условий диапазона?
Очевидно, что условие диапазона должно, по крайней мере, помнить, находится ли оно в данный момент в состоянии "поиск совпадения по первому адресу" или в состоянии "поиск совпадения по второму адресу". Возможно, нужно даже вспомнить третье состояние: "Я уже обработал диапазон и больше не буду совпадать, несмотря ни на что".
Это, безусловно, имеет значение, когда эти условия обновляются: каждый раз, когда читается новое пространство шаблонов? Каждый раз, когда пространство шаблона изменяется, скажем, с помощью s-команды? Или просто, если поток управления достигает условия диапазона?
Итак, что это?
Пока я не знаю лучше, я буду избегать условий диапазона в моих sed-скриптах и считаю их сомнительной функцией.
1 ответ
Два ответа:
0
неверный адрес POSIX (количество строк от 1)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
- Каждое совпадение поддерживает свое собственное состояние, так как несколько могут быть активны одновременно.
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
ЬурейеЕ.