Как убрать блок текста между 2 шаблонами? - PullRequest
0 голосов
/ 02 июля 2018

У меня есть следующий текст в моем файле

---BEGIN TEXT---
any text1
anytext2
anytext3
---END TEXT---
---BEGIN TEXT---
any text4
any text5
---END TEXT---

Я хочу удалить текстовый блок 2nd с "---BEGIN TEXT---" до "---END TEXT---"

Как мне это сделать с помощью команды linux

Так что мой файл будет содержать только:

---BEGIN TEXT---
any text1
anytext2
anytext3
---END TEXT---

Я знаю, как удалить 1-й блок с помощью следующей команды:

sed -n '/BEGIN TEXT/,/END TEXT/{p;/PAT2/q}' file.txt

Как я могу изменить мою sed команду для удаления 2-й части, а не первой? или используйте другую команду, например awk?

Ответы [ 6 ]

0 голосов
/ 02 июля 2018

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

sed -r '/---BEGIN/{:a;N;/^---END/M!ba;x;s/^/x/;/^x{2}$/{x;d};x}' file

Соберите строки между ---BEGIN и ---END, а затем увеличьте счетчик в области удержания (HS). Если счетчик равен 2, удалите коллекцию, иначе напечатайте как обычно.

0 голосов
/ 02 июля 2018

упрощенно, sed -i '/---END TEXT---/q;' txtfile хотя я не думаю, что это на самом деле ответ, который вы хотели.

Вы могли бы написать более сложный сценарий sed, который выполняет много манипуляций с удержанием и шаблонным пространством, но не так.

Если вы специально хотели исключить второй набор, вот способ, использующий только bash. Не лучше, чем ответы на awk, но мне нравится вносить разнообразие.

c=0; while read line; do [[ "$line" = "---BEGIN TEXT---" ]] && (( c++ )); (( c != 2 )) && echo "$line"; done <txt

или, отформатированный -

c=0
while read line
do [[ "$line" = "---BEGIN TEXT---" ]] && (( c++ ))
   (( c != 2 )) && echo "$line"
done < txtfile
0 голосов
/ 02 июля 2018

С GNU awk для мульти-символьных RS и RT:

$ awk -v RS='---END TEXT---\n' '{ORS=RT} NR==1' file
---BEGIN TEXT---
any text1
anytext2
anytext3
---END TEXT---

$ awk -v RS='---END TEXT---\n' '{ORS=RT} NR!=1' file
---BEGIN TEXT---
any text4
any text5
---END TEXT---

$ awk -v RS='---END TEXT---\n' '{ORS=RT} NR==2' file
---BEGIN TEXT---
any text4
any text5
---END TEXT---
0 голосов
/ 02 июля 2018

Вот модифицированный образец для общего решения

$ cat ip.txt 
foobaz
---BEGIN TEXT---
block 1
any text
---END TEXT---
1234567
---BEGIN TEXT---
block 2
any text
---END TEXT---
helloworld
---BEGIN TEXT---
block 3
any text
---END TEXT---
42424242

Чтобы удалить только второй блок:

$ awk -v b=2 '/BEGIN TEXT/{f=1; c++} !(f && c==b); /END TEXT/{f=0}' ip.txt 
foobaz
---BEGIN TEXT---
block 1
any text
---END TEXT---
1234567
helloworld
---BEGIN TEXT---
block 3
any text
---END TEXT---
42424242
  • -v b=2 удаляемый блок
  • /BEGIN TEXT/{f=1; c++} установка флага и счетчика приращений при совпадении начального регулярного выражения
  • /END TEXT/{f=0} очистить флаг для окончания регулярного выражения
  • !(f && c==b) не печатать входную запись, если установлен флаг и это блок, указанный в b variable


Дальнейшее чтение:

0 голосов
/ 02 июля 2018

Использование GNU awk и многострочная запись:

awk -v RS='---END TEXT---' 'NR==1{print $0 RT}' file

RS - разделитель записей, установленный в конце блока.

NR - номер записи. В этом случае нам нужен только первый.

RT - это терминатор записи, который хранит разделитель записей текущей записи и печатается вместе с требуемым блоком.

0 голосов
/ 02 июля 2018

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

awk '/BEGIN TEXT/{found++} found==1{print $0}' yourfile

awk обрабатывает файлы построчно. Итак, здесь мы проверяем, есть ли в текущей строке BEGIN TEXT. Если это так, мы увеличиваем переменную found на 1. В следующем блоке мы печатаем строку print $0, если переменная found равна 1.

Если файл большой и мы хотим остановить обработку после того, как found больше 1, мы можем добавить дополнительный блок для выхода

awk '/BEGIN TEXT/{found++} found==1{print $0} found>1{exit 0}' yourfile
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...