что делает эта команда sed: sed '1!G;h'

to add the corresponding strings in each and every file in the beginning of the file

bash+sedподход:

for f in *.md; do fn=${f##*-}; sed -i "1 s/^/${fn%.*} /" "$f"; done

  • fn=${f##*-}-усекает самую длинную совпавшую последовательность слева до последнего вхождения -(, например.abcd.md)

  • ${fn%.*}-усечение самой правой последовательности (с конца )до первого вхождения.(точки )из предыдущей подстроки fn(, т.е.abcd)

  • sed -i "1 s/^/${fn%.*} /" "$f"-добавить нужную строку в начало файла

0
16.11.2019, 15:06
3 ответа

Вы забываете, что Gдобавляется из области хранения, в которую пишет ваша первая команда, но не ваша вторая.

sed hне удваивает каждую строку, потому что просто перезаписывает пространство хранения в каждом цикле.

Ваша первая команда эквивалентна

sed '1!G;h' <<END_INPUT
alpha
beta
gamma
END_INPUT

и выходы

alpha
beta
alpha
gamma
beta
alpha

Для всех строк, кроме первой, текущее пространство хранения добавляется к пространству шаблона с разделяющим символом новой строки. Затем он перезаписывает пространство удержания пространством шаблона. В конце каждого цикла (после обработки строки ввода )выполняется неявная командаp(печати ).

Другой способ сказать, что «для каждой строки ввода он выводит все предыдущие строки в обратном порядке (с новой строкой последней )».

Таким образом, код будет

  1. прочитать alphaв пространство шаблонов, скопировать alphaв пространство хранения, распечатать alpha,
  2. прочитать betaв пространство шаблонов, добавить \nalphaв пространство шаблонов из пространства хранения, скопировать beta\nalphaв пространство хранения, распечатать beta\nalpha,
  3. прочитать gammaв пространство шаблонов, добавить \nbeta\nalphaв пространство шаблонов из пространства хранения, скопировать gamma\nbeta\nalphaв пространство хранения, напечатать gamma\nbeta\nalpha.

Код

sed '1!G' <<END_INPUT
alpha
beta
gamma
END_INPUT

выходы

alpha
beta

gamma

(третья и последняя строки пусты ).

Этот код sedвыводит каждую строку ввода и добавляет дополнительный символ новой строки ко всем строкам, кроме первой. Он делает это потому, что

  1. прочитать alphaв пространство шаблонов, напечатать alpha,
  2. прочитать betaв пространство шаблонов, добавить \nв пространство шаблонов из области хранения, напечатать beta\n,
  3. прочитать gammaв пространство шаблонов, добавить \nк пространству шаблонов из области удержания, напечатать gamma\n.

Обратите внимание, что добавление из пространства хранения с помощью Gздесь просто добавляет дополнительную новую строку в конце пространства шаблона, поскольку оно всегда пусто (, так как вы никогда не записываете в него ).

1
28.01.2020, 02:29

Начнем с чего-нибудь попроще:

$ seq 4 | sed 'G;h'
1

2
1

3
2
1

4
3
2
1

Каждый блок добавляет новое число и печатает его в обратном порядке.
Почему это происходит? Давайте медленно пройдемся по процессу:

  1. Первое число из seq (a1)(первая строка )получена sed. Эта линия помещается в пространство шаблона.
  2. Первой выполняемой командой является G, которая добавляет одну новую строку, за которой следует пробел к текущему пространству шаблонов. Сначала (, как и здесь ), пространство хранения пусто, поэтому sed добавляет новую строку и пустую строку (пространства хранения )к текущему пространству шаблонов. Короче говоря, он добавляет новую строку к первой строке ввода.
  3. Вторая команда h. Это копирует пространство шаблона в пространство удержания. Теперь пробел содержит 1, за которым следует новая строка.
  4. Список команд закончился, поэтому sed печатает пространство шаблонов (a 1, за которым следует новая строка ), потому что для sed нет опции -n. Затем он переходит к следующей строке ввода.
  5. Теперь sed получает вторую строку, 2, помещая ее в пространство шаблонов.
  6. Первая команда — G. Итак, sed добавляет пробел (a 1и новую строку, как указано выше, записанную в более короткой форме:1\n)к пространству шаблонов. Теперь пространство шаблонов содержит 2\n1\n.
  7. То, что содержится в пространстве шаблонов, печатается. Сед делает петлю назад.
  8. В третьей строке Gдобавляет \n2\n1\nк 3.
  9. Пространство шаблона 3\n2\n1\nкопируется в пространство хранения с помощью h.
  10. Кроме того, пространство шаблонов печатается в конце сценария sed.
  11. Цикл и повтор до последней строки.

Все вышеперечисленное сводится к захвату строк в обратном порядке.

Этот сценарий может прояснить ситуацию. (указать место шаблона с помощьюl):

$ seq 5 | sed -n 'G;h;l'
1\n$
2\n1\n$
3\n2\n1\n$
4\n3\n2\n1\n$
5\n4\n3\n2\n1\n$

И, как и в исходном скрипте, мы избегаем добавления новой строки в первой строке:

$ seq 5 | sed -n '1!G;h;l'
1$
2\n1$
3\n2\n1$
4\n3\n2\n1$
5\n4\n3\n2\n1$

Теперь, используя альфа, бета и гамму:

$ printf 'alpha\nbeta\ngamma' | sed -n '1!G;h;l'
alpha$
beta\nalpha$
gamma\nbeta\nalpha$

И мы возвращаемся к исходному скрипту sed:

$ printf 'alpha\nbeta\ngamma' | sed '1!G;h'
alpha
beta
alpha
gamma
beta
alpha

Что на самом деле, ИМО, должно было быть:

$ printf 'alpha\nbeta\ngamma' | sed '1!G;h;$!d'
gamma
beta
alpha

Печать только последней итерации со всеми строками в обратном порядке.

0
28.01.2020, 02:29

Я узнал, попробовав:

]# echo  -e "a\nb\nc\nd\ne\nf" |sed '1!G;h' 
a
b
a
c
b
a
d
c
b
a
e
d
c
b
a
f
e
d
c
b
a

Если читать задом наперёд :"abcdef", затем "abcde", затем "abcd", "abc", "ab", "a".

Как вы это называете?

Это работает, потому что "G" добавляет, а "h" заменяет. Если вы оставите только G;h, вы получите дополнительные пустые строки между этими блоками.


info sedесть пример "tac":

sed -n '1!G;$p;h'

При печати только один раз(-nи$p)результат будет совершенно другим :это последний "блок"sed '1!G;h'


Perl может легко имитировать этот алгоритм с (именованными )переменными:

]# echo -e "a\nb\nc" | perl -ne '$hold = $_. $hold; print $hold;'
a
b
a
c
b
a

Разворот возникает из-за того, что линия и сохраненные линии объединяются:

]# echo  -e "a\nb\nc" |perl -ne '$hold.= $_; print $hold;'
a
a
b
a
b
c

$_— входные строки. Это H=H+линия по сравнению с H=линия+H. Вы должны внимательно прочитать info sed, чтобы найти эту и другие тонкости.

1
28.01.2020, 02:29

Теги

Похожие вопросы