Что означает: a; $! N; в команде sed?

11
$ (echo hello; echo there) | sed ':a;$!N;s/\n/string/;ta'
hellostringthere

Выше sedкоманда заменяет символ новой строки на строку «строка». Но я не знаю значения :a;$!N;s/\n/string/;taвнутри одинарных кавычек. Я знаю среднюю часть s/\n/string/. Но я не знаю функции первой ( :a;$!N;) и последней ( ta) части.

Авинаш Радж
источник
2
пожалуйста, посмотрите на stackoverflow.com/questions/1251999/… .
xiaodongjie
Как насчет последней части?
Авинаш Радж
Команда "t" разветвляется на именованную метку, если последняя команда замещения изменила пространство шаблона.
xiaodongjie

Ответы:

17

Это, по общему признанию, загадочные sedкоманды. Конкретно (с man sed):

: label
         Метка для команд b и t.

t метка
         Если as /// выполнила успешную замену после того, как была прочитана последняя строка ввода и после последней команды t или T, то переход к метке; если метка опущена, переход к концу скрипта.

n N Прочитайте / добавьте следующую строку ввода в пространство шаблона.

Итак, скрипт, который вы разместили, может быть разбит на (пробелы добавлены для удобства чтения):

sed ':a;  $!N;  s/\n/string/;  ta'
     ---  ----  -------------  --
      |     |        |          |--> go back (`t`) to `a`
      |     |        |-------------> substitute newlines with `string`
      |     |----------------------> If this is not the last line (`$!`), append the 
      |                              next line to the pattern space.
      |----------------------------> Create the label `a`.

По сути, то, что это делает, можно записать в псевдокоде как

while (not end of line){
    append current line to this one and replace \n with 'string'
}

Вы можете понять это немного лучше с более сложным примером ввода:

$ printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;$!N;s/\n/string/;ta'
line1stringline2stringline3stringline4stringline5

Я не совсем уверен, зачем !$это нужно. Насколько я могу судить, вы можете получить тот же результат с

printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;N;s/\n/string/;ta'
terdon
источник
1
! $ Не соответствует последней новой строке, ИМО.
Брайам
@ Брайам не слишком уверен в этом, это $!не так !$. Впрочем, так может и быть, !Nи нет $!.
Тердон
Я пытался разобрать страницу TeXinfo - но не нашел ссылки на ни !Nили $!. Итак, я все еще продолжаю думать о том, смотрит ли последняя строка на новую строку или EOF.
Брайам
4
Я стараюсь думать о $!качестве адреса «диапазона» с оператором постфикса комплемента - так $!N(делают Nвезде , кроме адреса $) действительно имеет тот же синтаксис , как что - то вроде m,n!d(удалить все , кроме линий mдо n).
Steeldriver
:является аналогом gotoметки, и на самом деле :раньше использовался как метка goto в оболочке Томпсона, так что это было бы знакомо людям, использующим как sed, так и оболочку Томпсона
Сергей Колодяжный
0

Я отправляю этот ответ , так как я вижу много путаницы относительно почему последняя строка исключается при выполнении N(через адресации строки строки $!) и потому , что ОП был смущен о значении :a;$!N; в виде SED команды , а не только в к одной конкретной он отвечал ,

Что ж, преимущество использования $!Nвместо Nне является очевидным в предложенных примерах (OP и @terdon), поскольку в последней строке после Nкоманды «важная» (продолжайте чтение) команда не выполняется . (Действительно, результат тот же, если удалить этот адрес строки.)

В более сложном примере (например, замена this sentenceв файле, когда два слова появляются иногда в одной строке, а некоторые другие в двух строках), исключение последней строки для Nкоманды может иметь решающее значение! Если последняя строка не исключена, при выполнении Nна ней sedпроисходит EOFнемедленное нажатие клавиш и выход, что препятствует выполнению всех последующих команд (в том числе команд ветвления, а именно tи b).

В показанных слишком упрощенных примерах мы можем безопасно удалить $!и разрешить sedсбой при выполнении Nи возврате, поскольку прерванная sкоманда ничего не сделает, если она будет выполнена, так как нет \nсовпадений.

Энрико Мария Де Анжелис
источник