Вопрос или проблема
Я хочу удалить конкретные две последовательные строки, соответствующие шаблонам, из определенной строки файла.
Например, содержимое файла выглядит следующим образом.
Строка1: a
Строка2: b
Строка3: c
Строка4: Имя: 123
Строка5: xyz
Строка6: Имя: 456
Строка7: abc
Я хочу найти строки, начинающиеся с 4-й строки, соответствующие первому шаблону строки, начинающемуся с “Имя: “, и соответствующему второму шаблону строки, начинающемуся с пробела, и удалить эти две последовательные строки.
Есть ли какой-нибудь эффективный способ сделать это в shell с использованием sed
или чего-то другого?
Чтобы быть немного более ясным, я хочу удалить информацию о подписи/контрольной сумме из MANIFEST.MF.
Пример MANIFEST.MF выглядит следующим образом:
Из приведенного ниже файла манифеста я хочу удалить запись “Имя: “. где запись “Имя: ” может быть в одной строке или на 2 (или более) строках.
Изначально мое решение заключалось в том, чтобы найти первую запись “Имя: “, за которой следует запись “SHA-256-Digest: “, и удалить до конца файла. К сожалению, это решение имеет проблему удаления одной необходимой записи посередине. Например, “NetBeans-Simply-Convertible: ” также удаляется.
Теперь я хочу удалить запись “Имя: “, если она присутствует в 1 строке или запись, распространившуюся на 2 или более строк. Но я не должен терять записи такие как “NetBeans-Simply-Convertible: ” при удалении записей “Имя: “.
Я уже удаляю записи “SHA-256-Digest: ” с помощью следующей команды в файле sed -i "/^\SHA-256-Digest: /d" $manifest_file
Версия-манефеста: 1.0
Информация-версии: ....
Имя: com/abc/xyz/pqr/client/relationship/message/notifier/Relati
onshipUpdateNotifierFactory.class
SHA-256-Дайджест: cSSyk6Y2L2F9N6FPtswUkxjF2kelMkGe4bFprcQ+3uY=
Имя: com/abc/xyz/pqr/client/relationship/ui/BaseRelationshipView
$5.class
SHA-256-Дайджест: w9HgRjDuP024U4CyxeKPYFe6rzuzxZF3b+9LVG36XP8=
Имя: com/abc/xyz/pqr/client/impl/MofRelationshipAgentImpl.class
SHA-256-Дайджест: GwIBIU+UdPtjyRhayAVM90Eo+SwCT/kP65dI59adEnM=
Имя: com/abc/xyz/pqr/client/settings/ConvertibleProperties.class
NetBeans-Simply-Convertible: {com/abc/xyz/pqr/client/settings}Con
vertibleProperties
SHA-256-Дайджест: 5FszAtfpPXcLx/6FBWbfeg6E4fwFMRozV+Q+3rReATc= ...
Ожидаемый вывод:
Версия-манефеста: 1.0
Информация-версии: ....
NetBeans-Simply-Convertible: {com/abc/xyz/pqr/client/settings}Con
vertibleProperties
...
Подход с использованием awk:
Допустим, у нас есть следующий входной файл file.txt
(при этом каждая строка содержит Строка<номер>:
в качестве первого поля):
Строка1: a
Строка2: b
Строка3: c
Строка4: Имя: 123
Строка5: xyz
Строка6: Имя: 456
Строка7: abc
Строка8: Имя: 111
Строка9: www
Строка10: Num: 222
Строка11: abc
Строка12: Имя: 333
Строка13: ccc
awk '{ if ($2 == "Имя:") {
if ((getline l) > 0){
if (l ~ /^\S+ \S+/) { next } else { print $0 RS l }
}
} else { print }
}' file.txt
Вывод:
Строка1: a
Строка2: b
Строка3: c
Строка8: Имя: 111
Строка9: www
Строка10: Num: 222
Строка11: abc
‘getline var’ – считывает следующую запись из ввода awk в переменную var
Команда getline возвращает 1, если находит запись, и 0, если она встречает конец файла.
Вы видите, что то, что вы спрашиваете, неясно: один ответ удаляет 4 строки (две совпадающие и две последующие); другой удаляет всё кроме совпадающих строк…
Я скажу, что я понимаю, что вы хотите: я удаляю 2 строки, одну, соответствующую Имя: 123
, и последующую. Я делаю это с помощью sed
:
sed -e '/Имя: 123/{N;d}' название_файла
Используя ed
:
$ printf '%s\n' 'g/^ / s///\' '-,.j' 'g/^Имя: /d' 'g/SHA-256-Дайджест: /d' '4,$g/^$/d' ,p Q | ed -s файл
Версия-манефеста: 1.0
Информация-версии: ....
NetBeans-Simply-Convertible: {com/abc/xyz/pqr/client/settings}ConvertibleProperties
Это применяет следующий скрипт редактирования к вашему входному файлу:
g/^ / s///\
-,.j
g/^Имя: /d
g/SHA-256-Дайджест: /d
4,$g/^$/d
,p
Q
Это состоит из шести отдельных команд:
-
Две команды
s///
и-,.j
применяются к каждой строке, которая начинается с пробела. Пустое регулярное выражение в командеs
повторно использует выражение^
из предшествующей командыg
, которая используется для применения одной или нескольких команд к строкам, соответствующим регулярному выражению, поэтому командаs
удаляет первый пустой пробел на строках, которые начинаются с пустых пробелов. Затем командаj
соединяет измененную строку с предыдущей строкой. Это эффективно отменяет перенос строк в вводимых данных. -
Команда
d
применяется ко всем строкам, которые начинаются сИмя:
, удаляя их. -
Аналогично, строки, начинающиеся с
SHA-256-Дайджест:
, удаляются. -
Пустые строки удаляются начиная с 4-й строки.
-
Мы выводим полный буфер на стандартный вывод, чтобы отобразить результат.
-
Q
завершает работу редактора безусловно (вы можете использоватьwq
, чтобы записать изменения обратно в исходный файл).
sed -e '
4,$!d; # пропустить нерелевантную часть
/Имя:/N; # взять строку, следующую за Имя:
/\n.* /d; # то, что мы искали, не это
P;D
' ваш_файл
Ответ или решение
Для удаления двух последовательных строк, соответствующих определённым шаблонам, начиная с конкретной строки в файле, можно использовать стандартные инструменты командной строки, такие как sed
или awk
. В данном случае мы сосредоточимся на awk
, так как он предоставляет удобный способ обработки и фильтрации текстовых данных.
Пример задачи
Для демонстрации предположим, что у вас есть файл file.txt
с таким содержимым:
Line1: a
Line2: b
Line3: c
Line4: Name: 123
Line5: xyz
Line6: Name: 456
Line7: abc
Line8: Name: 111
Line9: www
Line10: Num: 222
Line11: abc
Line12: Name: 333
Line13: ccc
Цель
Ваша цель состоит в том, чтобы удалить строки, начинающиеся со слова "Name:" и следующие за ними строки (которые могут быть пустыми или содержать пробелы) для всех записей, начиная с четвёртой строки.
Решение с использованием awk
Вот пример команды awk
, которая справляется с этой задачей:
awk 'NR>=4 {
if ($1 == "Name:") {
getline;
next;
}
print;
}' file.txt
Разбор кода
NR>=4
– этот условный оператор гарантирует, что операции будут выполняться только с четвёртой строки и дальше.if ($1 == "Name:")
– проверяет, начинается ли текущая строка со слова "Name:".getline
– считывает следующую строку, что позволяет нам пропустить её и не выводить.next
– пропускает текущую итерацию, переходя к следующей строке.print
– выводит все строки, которые не соответствуют условиям удаления.
Пример выполнения
Используя приведённую выше команду, вы получите следующий вывод:
Line1: a
Line2: b
Line3: c
Line8: Name: 111
Line9: www
Line10: Num: 222
Line11: abc
Удаление конкретного шаблона
Если вы хотите удалить также строки, которые идут непосредственно после "SHA-256-Digest:", и гарантировать, что такие строки не будут удалены, используйте следующую конструкцию:
awk '/^Name:/ {
getline;
next;
}
/^SHA-256-Digest:/ {
next;
}
{
print;
}' file.txt
Изменения в формате файла "MANIFEST.MF"
Для файла, подобного вашему MANIFEST.MF
, где строки могут быть перенесены, например:
Name: com/abc/xyz/pqr/client/relationship/message/notifier/Relati
onshipUpdateNotifierFactory.class
SHA-256-Digest: cSSyk6Y2L2F9N6FPtswUkxjF2kelMkGe4bFprcQ+3uY=
Вам может понадобиться дополнительно объединить строки, которые были разбиты.
Заключение
Эти команды помогут вам эффективно удалить нужные строки из текстового файла, сохранив при этом структуру других данных. Используя awk
или аналогичные инструменты, вы можете легко управлять текстовыми файлами в автоматизированных сценариях. Этот подход обеспечивает гибкость и точность в обработке данных, что является важным аспектом для IT-специалистов.