sed: добавление после блока - PullRequest
0 голосов
/ 27 января 2019

Я очень новичок в sed, и все, что я нахожу, немного здесь, немного там.

У меня есть текстовый файл, который содержит блок, подобный следующему:

#start
a
b
c


#whatever
…

Очевидно, это упрощенная версия. Я хотел бы добавить строку в конец блока #start, чтобы получить:

#start
a
b
c
d

#whatever
…

Я могу отсортировать блок следующим образом:

sed -n '/^#\s*start/,/^$/ p' data.txt

так что я думаю, что это в правильном направлении. Тем не менее:

  • выбор включает пустую строку, которую я не хочу
  • Я не могу понять, как добавить еще одну строку после матча

Ответы [ 5 ]

0 голосов
/ 27 января 2019

С любым awk в любой оболочке на любой коробке UNIX:

$ awk 'BEGIN{RS=""; ORS="\n\n"; FS=OFS="\n"} $1=="#start"{$(NF+1)="d"} 1' file
#start
a
b
c
d

#whatever
…

В отличие от принятого в настоящее время решения sed, вышеприведенное будет работать, даже если целевая строка содержит метасимволы регулярных выражений и даже если добавляемая строка содержит обратные ссылки и даже если любая из них содержит разделители (/), и ее можно тривиально изменить сделать изменение на основе значения 2-й, 3-й или любой другой строки входного блока, а не только в дополнение к первой строке, и его можно тривиально изменить, чтобы добавить или изменить любую строку в середине блока , Короче говоря, это значительно лучший подход.

0 голосов
/ 27 января 2019

Это может сработать для вас (GNU sed):

sed '/^#start/,/^\s*$/!b;/^\s*$/c\d' file

Сфокусируйтесь на диапазоне строк между строкой, начинающейся #start, и пустой строкой. Если строка пуста, замените ее на d.

N.B. ! отрицает совпадение, а b без заполнителя освобождает от дальнейшей обработки с помощью sed.

Для сравнения обратите внимание на поведение этих решений, которое в первом случае добавляет d перед пустой строкой, а во втором добавляет d после пустой строки.

sed '/^#start/,/^\s*$/!b;/^\s*$/i\d' file

sed '/^#start/,/^\s*$/!b;/^\s*$/a\d' file
0 голосов
/ 27 января 2019

Вы можете использовать awk просто так:

awk -v RS= '/#start/{$0 = $0 ORS "d\n"} 1' file

Если #start не в верхней части файла, то вы захотите сделать:

awk -v RS= '/#start/{$0 = $0 ORS "d"} {$0 = $0 ORS} 1' file

* Это удаляет все, кроме одного перевода строки между каждым блоком.

Результат :

#start
a
b
c
d

#whatever
…
0 голосов
/ 27 января 2019

С седом:

sed '/#start/,/^$/ s/^$/d/;' file
  • /#start/,/^$/: поиск блоков, начинающихся с #start и заканчивающихся пустой строкой
  • s/^$/d/: заменить соответствующую пустую строку на d

Если вы хотите добавить строку перед пустой строкой:

sed '/#start/,/^$/{/^$/{s//d/;G;};}' file
0 голосов
/ 27 января 2019

Для GNU sed попробуйте это (обновите снова, была небольшая ошибка):

sed '/^#\s*start/{x;s/.*/d/;x;be};/^\s*#[a-zA-Z]*/{x;G;x;s/.*//;x;};/^\s*$/{x;};:e'

Например:

$ cat file                                                               
#start                                                                   
a                                                                        
b                                                                        
c                                                                        


#whatever                                                                
...                                                                      

$ cat file2                                                              
#start                                                                   
a                                                                        
b                                                                        
c                                                                        
#whatever                                                                
...                                                                                                       
$ sed '/^#\s*start/{x;s/.*/d/;x;be};/^\s*#[a-zA-Z]*/{x;G;x;s/.*//;x;};/^\s*$/{x;};:e' file  
#start                                                                   
a                                                                        
b                                                                        
c                                                                        
d                                                                        


#whatever                                                                
...                                                                      

$ sed '/^#\s*start/{x;s/.*/d/;x;be};/^\s*#[a-zA-Z]*/{x;G;x;s/.*//;x;};/^\s*$/{x;};:e' file2 
#start                                                                   
a                                                                        
b                                                                        
c                                                                        
d                                                                        
#whatever                                                                
...      

Эта команда sed перетасует эти not-so-empty пустые строки (только пробелы).Но я думаю, это нормально для вас, не так ли?
Идея состоит в том, чтобы использовать hold space, чтобы оставить нужную вещь нужной (d здесь), и добавить ее, когда придет время.
x заключается в обменеhold space с pattern space (текущая строка для чтения).

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

...