Как удалить строки в файле, если в файле нужно сравнить более одного символа в разных строках?

Я столкнулся с этим в 2017 году с Linux Mint 18.1 (Serena ), поэтому я думаю, что это заслуживает обновленного ответа. Эта проблема была зарегистрирована как Github issue #1429 и как ошибка Launchpad#1592293 .

Исправление появилось вместе с этой фиксацией , которая была помечена как версия 3.4.2 Nemo, так что это должна быть выпущенная версия, исправляющая проблему.

Решение этой проблемы состоит в том, чтобы просто получить обновленную версию Nemo. Обновление до последней версии Linux Mint (18.2 )должно быть достаточным; однако в примечаниях к выпуску не указано, какая именно версия Nemo включена.

-2
14.11.2019, 11:38
2 ответа
awk '$0 !~/Fine|Doing/' i.txt  

выход

Hi
Its Been Long Time
0
28.04.2021, 23:27

Чтобы удалить все строки, содержащие слова Doingили Fine, вы можете использовать grepследующим образом:

grep -Fw -v -e 'Doing' -e 'Fine' file

Опция -Fзаставляет grepиспользовать заданные выражения как строки , а не как регулярные выражения, а -wзаставляет сопоставлять целые слова (, а не подстроки других слов, например Doingsили Fines). Опция -vинвертирует смысл теста, так что строки, соответствующие заданным выражениям, удаляются из вывода. Две строки задаются с помощью -e, который используется для получения выражения для запроса с помощью (. Этот параметр часто опускается, но здесь он необходим, поскольку у нас их два ).


С помощью sedможно сделать

sed -e '/\<Doing\>/d' -e '/\<Fine\>/d' file

или

sed '/\<Doing\>/d; /\<Fine\>/d' file

или

sed -E '/\<(Doing|Fine)\>/d' file

Каждый из них соответствует двум строкам как словам. Специальные шаблоны \<и \>соответствуют пробелу нулевой ширины -в начале и конце слова соответственно (пробелу между символом слова -и символом, отличным от -слова -). В GNU sedвы можете использовать \bвместо \<и \>.

Последняя команда sedиспользует чередование для соответствия любому слову. Чередование — это функция расширенных регулярных выражений, поэтому мы включаем их с помощью -Eв командной строке.

Во всех случаях шаблон сопоставляется с каждой строкой ввода, и если он совпадает, он удаляется с помощью команды d. Все остальные строки печатаются.

Обратное, вывод всех строк, которые не совпадают, и игнорирование остальных, может быть выполнено с помощью

sed -n -E '/\<(Doing|Fine)\>/!p' file

То есть отключите вывод данных по умолчанию с помощью -nи затем печатайте(p)только те строки, которые не соответствуют(!)шаблону.


Код awkбудет выглядеть очень похожим на код sedс использованием расширенных регулярных выражений,по крайней мере, при использовании GNU awk(, который понимает \<и\>):

awk '!/\<(Doing|Fine)\>/' file

или

awk '!/\<Doing\>/ && !/\<Fine\>/' file

Они оба пытаются сопоставить два слова с входными данными и не будут печатать данные, если слова присутствуют.

Вы также можете использовать функцию index()в awk, но это также будет находить слова как подстроки (, точно так же, как с помощью /(Doing|Fine)/):

awk '!index($0, "Doing") && !index($0, "Fine")' file

index($0, string)возвращает ноль, если stringне найдено в$0(всей строке ), поэтому отрицание результата с помощью !даст вам истинное значение, если строка не была нашел.

Длинный -способ сделать это в awk— проверить каждое поле отдельно:

awk '{ for (i = 1; i <= NF; ++i) if ($i == "Doing" || $i == "Fine") next; print }' file

Это проверяет каждое поле на наличие двух слов и сразу же переходит к следующей строке ввода, если одно из них найдено. В противном случае строка печатается.

Это дало бы результаты, отличные от использования /\<(Doing|Fine)\>/, если бы в тексте присутствовало такое слово, как A-Doing. Цикл не заметит его (, потому что поля разделены пробелами ), но регулярное выражение заметит (, потому что -не является -символом слова -).

0
28.04.2021, 23:27

Теги

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