Как команда sed '1! G; h; $! D' переворачивает содержимое файла?


20

Мой вопрос связан с sed-специфическим решением, данным в этом ответе на этот вопрос обратного сопоставления . sed/ grepРешение , которое я не могу расшифровать это следующим:

sed '1!G;h;$!d' file

Может кто-нибудь, пожалуйста, расшифровать эту команду?

Из знаний VI (M) я знаю, что G обозначает последнюю строку файла и что в sed «bang» (!), За которым следует адрес, немного похожий на grep -vто, чтобы сказать, что он не будет соответствовать этой строке. Но в целом приведенный выше сценарий sed выше моего понимания.


3
... очень медленно ...
mikeserv

1
Как намеки Микесерв. Следует отметить, что этот хитрый sedрецепт является чрезвычайно неэффективным способом (O (n ^ 2/2) сложность), чтобы перевернуть строки в файле. Это было бы слишком медленно для файлов с большим количеством строк. Гораздо более эффективную альтернативу реверсирования порядка строк смотрите в tacGNU coreutils.
Ариэльф

Ответы:


35

Это переворачивает файл строка за строкой.

Файл sed '1! G; h; $! d'

Во-первых, sedимеет место для удержания и шаблонное пространство . Мы должны различать их, прежде чем сосредоточиться на этой конкретной команде.

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


Команде:

Есть 3 команды в этом заявлении: 1!G, hи$!d

  • 1!Gозначает, что Gкоманда выполняется в каждой строке, кроме первой ( !отрицает 1). Gозначает добавить то, что находится в удерживающем пространстве в пространство образца.

  • hотносится к каждой строке. Он копирует пространство шаблона в пространство удержания (и перезаписывает его).

  • $!dприменяется к каждой строке, кроме последней ( $представляет последнюю строку, !отрицает ее). dэто команда для удаления строки (пробел).


  1. Теперь, когда первая строка прочитана, sedвыполняется hкоманда. Первая строка копируется в область удержания. Затем он удаляется, так как он соответствует $!условию. sedпродолжается со второй строки.
  2. Вторая строка соответствует условию 1!(это не первая строка), и поэтому пространство удержания (которое имеет первую строку) добавляется к пространству шаблона (которое имеет вторую строку). После этого в шаблонном пространстве появляется вторая строка, за которой следует первая строка, разделенная новой строкой. Теперь hкоманда применяется (как в каждой строке); все, что находится в пространстве образца, копируется в пространство удержания. Применяется третье утверждение ( $!d): строка удаляется из пространства шаблона.
  3. Шаг 2 теперь выполняется со всеми строками. Переходим к последней строке.
  4. В последней строке ( $) почти весь шаг 2 выполнен, но не часть удаления ( d). sed, при вызове без -n, автоматически печатает пространство шаблона в конце обработки для каждой строки ввода. Таким образом, когда не удаляется, пространство шаблона печатается. Теперь он содержит все строки в обратном порядке .

1
@Geek Нет, hкоманда копирует пространство шаблона в пространство удержания, которое сохраняется доsed конца. После окончания скрипта все очищается, потому что бинарный файл вышел.
хаос

2
Можем ли мы представить пространство хранения как регистры для vim? Они также пронумерованы? Или есть только один из них?
Компьютерщик

2
@Geek В sedтам только один пробел. Это как переменная, которая может содержать что-то.
хаос

1
@ user1717828 Если мы не будем, первая строка будет напечатана при обработке. Поскольку sed не вызывается с помощью, -nмы должны удалить каждую строку, кроме последней. В последней строке sed добавляет все из пространства удержания в пространство шаблона. И поскольку dкоманда не будет выполнена, строка печатается (теперь эта строка содержит весь файл в обратном порядке).
хаос

1
(1) Подвопрос / наблюдение ФП (в комментарии) таков: «поэтому hкоманда в последней строке вроде неактивна» (с дополнительным акцентом и слегка перефразированным). Он прав; Когда sedобрабатывается последняя строка ввода , Gсчитывается пространство удержания (для добавления его в пространство образца), а затем hкопируется пространство образца в пространство удержания, на которое никогда больше не ссылаются . Мы могли бы также сказать sed 'G;$!h;$!d'или sed 'G;$!{h;d}'. (2) Мы могли бы избежать использования d, говоря sed -n 'G;h;$p'.
Скотт
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.