Как удалить строку, если она содержит символ ровно один раз

Решение, аналогичное @ iñaki-murillo, но с использованием / proc / pid / cmdline вместо ps и grep . Я также использую $ NF и предполагаю, что последнее поле находится в формате pid / procname , а не предполагаю, что это 7 долларов (на самом деле в моей системе это было 6 долларов).

netstat -putan|awk '/master/ {split($NF, pid,"/");sub(FS $NF,x);getline cmd < ("/proc/"pid[1]"/cmdline");print $0" "pid[1]"/"cmd}'

Объяснение

/ master / Фильтр по строкам, содержащим master.

split ($ NF, pid, "/"); Разделить последнее поле на / и сохранить в pid

sub (FS $ NF, x); Удалить последнее поле.

getline cmd <("/ proc /" pid [1] "/ cmdline") Прочтите вызов командной строки для рассматриваемого pid и сохраните его в cmd .

print $ 0 "" pid [1] "/" cmd Распечатать все

10
02.05.2017, 08:26
8 ответов
sed -e '
  s/C/&/2;t   # when 2nd C matches skip processing and print
  /C/d        # either one C or no C, so delete on C
'

sed -e '
   /C/!b     # no C, skip processing and print
   /C.*C/!d  # not(at least 2 C) => 1 C => delete
'

perl -lne 's/C/C/g == 1 or print'
2
27.01.2020, 19:59

Это удаляет строки, содержащие только одно вхождение C.

grep -v '^[^C]*C[^C]*$' file

Регулярное выражение [^C] соответствует одному символу, который не является C (или новой строкой), и оператору повторения (также известному как Kleene звездочка) * указывает ноль или более повторений предыдущего выражения.

По умолчанию вывод grep (и большинства других текстовых инструментов) — стандартный вывод; перенаправить на новый файл и, возможно, переместить его поверх исходного файла, если вы этого хотите. То же самое регулярное выражение можно использовать с sed -i для редактирования на месте:

sed -i '/^[^C]*C[^C]*$/d' file

(На некоторых платформах, особенно *BSD, включая macOS, параметр -i требует аргумента, например -i ''.)

6
27.01.2020, 19:59

В awk вы можете установить любой разделитель полей. Если вы установите для него значение C, то у вас будет столько полей +1, сколько вхождений C.

Таким образом, если вы скажете awk -F'C' '{print NF}' <<< "C1C2C3", вы получите 4: CCC состоит из 3 Cs и, следовательно, 4 поля.

Вы хотите удалить строки, в которых C встречается ровно один раз. Учитывая это, в вашем случае вы захотите удалить те строки, в которых ровно два C-поля.Так что просто пропустите их:

$ awk -F'C' 'NF!=2' file
DTHGTY
HYTRHD
HTCCYD
20
27.01.2020, 19:59

Для тех, кто хочет конкретно awk, я бы предложил

awk '/C[^C]*C/{next}//{print}'

пропустить строку, если она соответствует шаблону, иначе напечатать ее. На самом деле вам не нужно {print}, вы можете использовать // и печать по умолчанию, но я думаю, что это более понятно.

Моей первой мыслью было использовать egrep -v с тем же шаблоном, но это на самом деле не отвечает на заданный вопрос.

1
27.01.2020, 19:59

sed подход:

sed -i '/^[^C]*C[^C]*$/d' input

-i опция позволяет модифицировать файл на месте

/^[^C]*C[^C]*$/ — соответствует строкам, содержащим C только один раз

d - удалить совпадающие строки

8
27.01.2020, 19:59

Это можно сделать с помощью sed как:

Код:

sed '/C.*C/p;/C/d' file1

Результаты:

DTHGTY
HYTRHD
HTCCYD

Как?

  1. Найдите и напечатайте любую строку, содержащую не менее двух копий C через /C.*C/p
  2. Удалить любую строку с C через /C/d, сюда входят строки, уже напечатанные на шаге 1
  3. По умолчанию печатать остальные строки
8
27.01.2020, 19:59

Инструмент POSIX для редактирования файла по сценарию (вместо того, чтобы печатать измененное содержимое в стандартный вывод) ex.

printf '%s\n' 'g/^[^C]*C[^C]*$/d' x | ex file.txt

Конечно, вы можете использовать sed -i , если ваша версия Sed поддерживает это, просто имейте в виду, что это не переносимо, если вы пишете скрипт, предназначенный для работы на разных типах систем. .


Дэвид Форстер спросил в комментариях:

Есть ли причина, по которой вы используете printf, а не echo или что-то вроде ex -c COMMAND ]?

Ответ: Да.

Для printf и echo это вопрос переносимости; см. Почему printf лучше, чем echo? Кроме того, легче вставлять символы новой строки между командами, используя printf.

Для printf ... | ex vs. ex -c ... , это вопрос обработки ошибок.Для этой конкретной команды это не имеет значения, но в целом имеет значение; например, попробуйте поместить

ex -c '%s/this pattern is not in the file/replacement text/g | x' filename

в скрипт. В отличие от следующего:

printf '%s\n' '%s/no matching lines/replacement/g' x | ex file

Первый будет зависать и ждать ввода; второй завершится, когда команда ex получит EOF, поэтому сценарий продолжится. Существуют альтернативные обходные пути, такие как s///e, но они не указаны в POSIX. Я предпочитаю использовать портативную форму, показанную выше.

Для команды g в конце должна быть новая строка, и я предпочитаю использовать printf для переноса команд, а не вставлять новую строку в одинарные кавычки.

4
27.01.2020, 19:59

Вот несколько вариантов использования perl.

Поскольку вы сопоставляете только один символ, вы можете использовать tr/C// (перевод без замены), чтобы вернуть количество совпадений C :

perl -lne 'print if tr/C// != 1' file

В более общем случае, если вы хотите сопоставить многосимвольную строку или регулярное выражение, вы можете использовать это:

perl -lne 'print if (@m = /C/g) != 1' file

Это присваивает совпадения регулярного выражения /C/g list @m и выводит строки, если длина этого списка не равна 1.

Переключатель -i можно добавить для редактирования «на месте».

2
27.01.2020, 19:59

Теги

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