Я хочу удалить строку из файла, который содержит определенный символ только один раз, если он присутствует более одного раза или отсутствует, то сохранить строку в файле.
Например:
DTHGTY
FGTHDC
HYTRHD
HTCCYD
JUTDYC
Здесь символ, который я хочу удалить C
, таков: команда должна удалять строки FGTHDC
и JUTDYC
потому, что они есть C
ровно один раз.
Как я могу сделать это, используя sed
или awk
?
источник
awk
разделителя полей!awk 'BEGIN { print "FS={" FS"}","OFS={" OFS "}";} {printf "%d fields : ",NF; for (i=1;i<=NF;i++) {printf "{" $i "} ";}; print "" }'
и накормить несколько строк, некоторые из которых имеют несколько spces, а другие начинаются с пробела (ов))Сед подход:
-i
опция позволяет модифицировать файл на месте/^[^C]*C[^C]*$/
- сопоставляет строки, содержащиеC
только один разd
- удалить совпавшие строкиисточник
Это можно сделать с помощью
sed
:Код:
Полученные результаты:
Как?
C
через/C.*C/p
C
via/C/d
, включая строки, уже напечатанные на шаге 1источник
Это удаляет строки только с одним вхождением C.
Регулярное выражение
[^C]
соответствует одному символу, который не является символом C (или новой строкой), а оператор повторения (он же звезда Клини)*
задает ноль или более повторений предыдущего выражения.Вывод по умолчанию
grep
(и большинства других текстовых инструментов) - стандартный вывод; перенаправить на новый файл и, возможно, переместить его поверх исходного файла, если вы этого хотите. То же самое регулярное выражение можно использоватьsed -i
для редактирования на месте:(На некоторых платформах, особенно * BSD, включая macOS,
-i
опция требует аргумент, например-i ''
.)источник
sed -i '/^[^C]*C[^C]*$/d' file
- Похоже, это было опубликовано ранее, как вы думаете, плагиат?grep
ответа, но он, очевидно, легко распространяется наsed -i
вариант. Не видел ваш ответ, потому что я искал предыдущиеgrep
ответы.-i
сsed
и вместо того, чтобы перенаправить в новый файл и заменить оригинал с тем , еслиsed
утилита вышла без ошибок.grep -vx '[^C]*C[^C]*'
grep
потому что это яснее и надежнее (в частности,sed
имеет менее информативный код выхода).Инструмент POSIX для редактирования файла по сценарию (вместо печати измененного содержимого в стандартный формат)
ex
.Конечно, вы можете использовать,
sed -i
если ваша версия Sed поддерживает это, просто имейте в виду, что это не переносимо, если вы пишете сценарий, предназначенный для запуска в разных типах систем.Дэвид Фёрстер спросил в комментариях:
Ответ: да.
Для
printf
противecho
это вопрос переносимости; Посмотрите, почему printf лучше, чем echo? И также легче перемежать переводы строк между командами, использующимиprintf
.Для
printf ... | ex
противex -c ...
, это вопрос обработки ошибок. Для этой конкретной команды это не имеет значения, но в целом это имеет значение; например, попробуйте положитьв сценарии. Сравните это со следующим:
Первый будет зависать и ждать ввода; второй завершится, когда команда получит EOF
ex
, поэтому сценарий продолжится. Существуют альтернативные обходные пути, напримерs///e
, но они не указаны в POSIX. Я предпочитаю использовать переносную форму, которая показана выше.Для
g
команды в конце должен быть символ новой строки, и я предпочитаю использоватьprintf
для переноса команд, а не вставлять новую строку в одинарные кавычки.источник
printf
а неecho
или что-то подобноеex -c COMMAND
?printf
противecho
(хотя я обычно предпочитаю,echo
когда аргумент жестко запрограммирован), но я до сих пор не использовалex
широко.Вот несколько вариантов использования Perl.
Поскольку вы сопоставляете только один символ, вы можете использовать
tr/C//
(перевод, без замен), чтобы вернуть количество совпаденийC
:В более общем случае, если вы хотите сопоставить многосимвольную строку или регулярное выражение, вы можете использовать это:
Это назначает совпадения регулярного выражения
/C/g
списку@m
и печатает строки, когда длина этого списка не равна1
.-i
Переключатель может быть добавлена возможность редактирования «на месте».источник
источник
sed
,t #...
что GNU , как правило , будет переходить к метке, вызываемой#...
в большинстве другихsed
реализаций.!b
GNU sed, так как ветке не нравится ничего, кроме метки или новой строки после него.b
,t
,:
,}
(иr file
,w file
...) не может иметь команду после них на одной и той же линии. Вы также можете использовать отдельные-e
параметры.g
модификатор.Для тех, кто хочет
awk
конкретно, я бы предложилпропустите строку, если она соответствует шаблону, выведите ее в противном случае. Вам на самом деле не нужно
{print}
, вы можете использовать//
и печать по умолчанию, но я думаю, что это более четко прописано.Моей первой мыслью было использовать
egrep -v
тот же шаблон, но на самом деле это не отвечает на поставленный вопрос.источник
{next}
? Просто скажите,awk '/pattern/ {next} 1'
и все строки, не соответствующие шаблону, будут напечатаны. Или лучшеawk '!/pattern/'
распечатать их напрямую.!/pattern/
(что почему-то ускользнуло от меня), но я бы предпочел увидеть объяснения, а//{print}
не загадку1
. Предполагайте наименьшую компетентность и беглость от следующего человека, чтобы поддерживать ваш код, в соответствии с тем, чтобы не сделать его серьезно менее эффективным или действенным.