sed для замены строк, совпадающих с диапазоном шаблонов, если одна строка соответствует условию

#python #regex #linux #sed #scripting

#python #регулярное выражение #linux #sed #сценарии

Вопрос:

Мне нужно удалить запись в следующем формате файла примера:

 record {
    record {
        my_id_1
        my_name_1
    }
    
    record {
        my_id_2
        my_name_2
    }
    
    record {
        my_id_3
        my_name_3
    }
}
 

Нам нужно удалить все данные записи, используя уникальное значение my_id или my_id_2 в этом случае, и ожидаемый результат должен быть:

 record {
    record {
        my_id_1
        my_name_1
    }
    
    record {
        my_id_3
        my_name_3
    }
}
 

Примечание: файл не является стандартом, говорящим о пробелах, новых строках и т. Д. Но основная логика может заключаться в удалении всего, что находится между словом record [включая одно и то же слово], которое относится только к my_id_* строке в скобках.

Все, что я смог сделать до сих пор, это написать:

 sed -n '/record/{:a;N;/}/!ba; /my_id_2/p}' file.conf
 

это, по сути, находит то, что мне нужно, но я не могу это удалить, я печатаю только те строки, которые хочу очистить.

sed это мой основной вариант, но он также python regex может подойти, так что я могу передать его в ansible.

##########################

ЭТО ТАКЖЕ МОЯ ПОПЫТКА PYTHON

##########################

ИНСТРУМЕНТ: https://pythex.org /

используя python, это было самое близкое, что я получил:

сначала попробуйте: (?=my_id_2)([^}] )(?=})

с результатом матча:

     `my_id_2 my_name_2`
 

затем немного изменен:
(?=record )([^}] )(?=})

с результатом матча:

Match 1

     `1. record { record { my_id_1 my_name_1`
 

Match 2

     `1. record { my_id_2 my_name_2`
 

Match 3

 `1. record { my_id_3 my_name_3`
 

Спасибо.

Комментарии:

1.используя python, это было самое близкое, что я получил: первая попытка: (?=my_id_2)([^}] )(?=}) с результатом соответствия: my_id_2 my_name_2 затем немного изменено: (?=record )([^}] )(?=}) с результатом соответствия: Match 1 1. record { record { my_id_1 my_name_1 Match 2 1. record { my_id_2 my_name_2 Match 3 1. record { my_id_3 my_name_3

Ответ №1:

Вы могли бы попробовать:

 $ sed -i.bak '/record/{:a;N;/}/!ba; /my_id_2/d}' file.conf
$ cat file.conf
record {
    record {
        my_id_1
        my_name_1
    }
    
    
    record {
        my_id_3
        my_name_3
    }
}
 

Приведенное выше действие изменяет файл на месте и создает резервную копию файла с именем file.conf.bak . Если вам не нужна резервная копия исходного файла, вы можете удалить .bak из -i.bak .

Ответ №2:

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

 sed '/./{H;$!d} ;x; /my_id_2/d' file.conf
 

Можно подумать, что вы могли бы просто удалить его с ; 1d добавлением дополнительного к вашему заявлению sed.

 sed '/./{H;$!d} ;x; /my_id_2/d ; 1d' file.conf
 

Однако это не имеет никакого эффекта, и строка 1 по-прежнему остается пустой. Вы можете преодолеть это, передав его последующей sed команде, но это кажется ненадежным. Может быть, кто-то еще знает почему.

 sed '/./{H;$!d} ;x; /my_id_2/d' file.conf | sed '1d'
 

https://www.gnu.org/software/sed/manual/sed.html

Ответ №3:

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

 sed -E '/record {/{:a;N;/}/!ba;/my_id_2/!b;s/(record {.*)1.*/1/;t;d}' file
 

Используйте свой оригинальный подход, но проведите дополнительный тест с использованием greed, который в случае успеха сохраняет начало соответствующих строк. Если такого совпадения нет, вернитесь и, как и раньше, удалите всю соответствующую строку.

Примечание. Это может привести к некоторому нежелательному заполнению, удаление которого оставлено в качестве упражнения для читателя 😉