Удалить строки в текстовом файле, которые содержат определенную строку

Как бы я использовал sed, чтобы удалить все строки в текстовом файле, которые содержат определенную строку?

21 ответ

Решение

Чтобы удалить строку и распечатать вывод на стандартный вывод:

sed '/pattern to match/d' ./infile

Чтобы напрямую изменить файл:

sed -i '/pattern to match/d' ./infile

Чтобы напрямую изменить файл (и создать резервную копию):

sed -i.bak '/pattern to match/d' ./infile

Для пользователей Mac OS X и FreeBSD:

sed -i '' '/pattern/d' ./infile

Есть много других способов удаления строк с определенной строкой, кроме sed:

AWK

awk '!/pattern/' file > temp && mv temp file

Рубин (1,9+)

ruby -i.bak -ne 'print if not /test/' file

Perl

perl -ni.bak -e "print unless /pattern/" file

Shell (Баш 3.2 и позже)

while read -r line
do
  [[ ! $line =~ pattern ]] && echo "$line"
done <file > o
mv o file

GNU grep

grep -v "pattern" file > temp && mv temp file

И конечно sed (обратная печать выполняется быстрее, чем фактическое удаление):

sed -n '/pattern/!p' file

Вы можете использовать sed, чтобы заменить строки в файле. Тем не менее, это кажется намного медленнее, чем использование grep для обратного преобразования во второй файл, а затем перемещение второго файла поверх оригинала.

например

sed -i '/pattern/d' filename      

или же

grep -v "pattern" filename > filename2; mv filename2 filename

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

Самый простой способ сделать это с помощью GNU sed:

sed --in-place '/some string here/d' yourfile

Вы можете рассмотреть возможность использования ex (который является стандартным командным редактором Unix):

ex +g/match/d -cwq file

где:

  • + выполняет заданную команду Ex (man ex), такой же как -c который выполняет wq (написать и выйти)
  • g/match/d - Ex команда для удаления строк с заданным match см.: Сила г

Приведенный выше пример представляет собой POSIX-совместимый метод для редактирования файла на месте согласно этому посту в спецификациях Unix.SE и POSIX для ex,


Разница с sed в том, что:

sed является редактором S Tream ED, а не редактором файлов. BashFAQ

Если вам не нравится непереносимый код, накладные расходы ввода-вывода и некоторые другие плохие побочные эффекты. Так что в основном некоторые параметры (такие как на месте / -i) являются нестандартными расширениями FreeBSD и могут быть недоступны в других операционных системах.

Я боролся с этим на Mac. Кроме того, мне нужно было сделать это с помощью замены переменных.

Поэтому я использовал:

sed -i '' "/$pattern/d" $file

где $file это файл, в котором требуется удаление и $pattern шаблон для сопоставления для удаления.

Я выбрал '' из этого комментария.

Здесь следует отметить использование двойных кавычек в "/$pattern/d", Переменная не будет работать, когда мы используем одинарные кавычки.

Вы также можете использовать это:

 grep -v 'pattern' filename

Вот -v будет печатать только ваш шаблон (что означает инвертированное совпадение).

Чтобы получить такой же результат с grep вы можете сделать это:

echo "$(grep -v "pattern" filename)" >filename

Удалить строки из всех файлов, соответствующих совпадению

      grep -rl 'text_to_search' . | xargs sed -i '/text_to_search/d'

Я сделал небольшой тест с файлом, который содержит примерно 345 000 строк. Путь с grep кажется, примерно в 15 раз быстрее, чем sed метод в этом случае.

Я пробовал как с настройкой LC_ALL=C, так и без нее, кажется, что изменения времени существенно не изменились. Строка поиска (CDGA_00004.pdbqt.gz.tar) находится где-то посередине файла.

Вот команды и время:

time sed -i "/CDGA_00004.pdbqt.gz.tar/d" /tmp/input.txt

real    0m0.711s
user    0m0.179s
sys     0m0.530s

time perl -ni -e 'print unless /CDGA_00004.pdbqt.gz.tar/' /tmp/input.txt

real    0m0.105s
user    0m0.088s
sys     0m0.016s

time (grep -v CDGA_00004.pdbqt.gz.tar /tmp/input.txt > /tmp/input.tmp; mv /tmp/input.tmp /tmp/input.txt )

real    0m0.046s
user    0m0.014s
sys     0m0.019s

SED:

  • '/James\|John/d'
  • -n '/James\|John/!p'

AWK:

  • '!/James|John/'
  • /James|John/ {next;} {print}

GREP:

  • -v 'James\|John'

Вы также можете удалить ряд строк в файле. Например, чтобы удалить хранимые процедуры в файле SQL.

sed '/CREATE PROCEDURE.*/,/END ;/d' sqllines.sql

Это удалит все строки между CREATE PROCEDURE и END;.

Я очистил много файлов sql с помощью этой команды sed.

perl -i    -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3

Первая команда редактирует файл (ы) на месте (-i).

Вторая команда делает то же самое, но сохраняет копию или резервную копию исходного файла (ов), добавляя.bk к именам файлов (.bk можно изменить на что угодно).

echo -e "/thing_to_delete\ndd\033:x\n" | vim file_to_edit.txt

Как ни странно, принятый ответ на самом деле не дает прямого ответа на вопрос. Вопрос касается использования sed для замены строки, но ответ, похоже, предполагает знание того, как преобразовать произвольную строку в регулярное выражение.

Многие библиотеки языков программирования имеют функцию для выполнения такого преобразования, например

python: re.escape(STRING)
ruby: Regexp.escape(STRING)
java:  Pattern.quote(STRING)

Но как это сделать в командной строке?

Поскольку это вопрос, ориентированный на sed, одним из подходов было бы использование самого sed:

sed 's/\([\[/({.*+^$?]\)/\\\1/g'

Итак, для произвольной строки $STRING мы могли бы написать что-то вроде:

re=$(sed 's/\([\[({.*+^$?]\)/\\\1/g' <<< "$STRING")
sed "/$re/d" FILE

или как однострочный:

 sed "/$(sed 's/\([\[/({.*+^$?]\)/\\\1/g' <<< "$STRING")/d" 

с вариантами, описанными в другом месте на этой странице.

Я нашел большинство ответов бесполезными для меня. Если вы используете vim, я нашел это очень простым и понятным:

:g/<pattern>/d

Источник

На всякий случай, если кто-то хочет сделать это для точного соответствия строк, вы можете использовать -w флаг в grep - w для всего. То есть, например, если вы хотите удалить строки с номером 11, но оставить строки с номером 111:

-bash-4.1$ head file
1
11
111

-bash-4.1$ grep -v "11" file
1

-bash-4.1$ grep -w -v "11" file
1
111

Это также работает с -f Отметить, если вы хотите исключить несколько точных шаблонов одновременно. Если "черный список" - это файл с несколькими шаблонами в каждой строке, который вы хотите удалить из "файла":

grep -w -v -f blacklist file

Показать обработанный текст в консоли

cat filename | sed '/text to remove/d' 

сохранить обработанный текст в файл

cat filename | sed '/text to remove/d' > newfile

для добавления обработанной текстовой информации в существующий файл

cat filename | sed '/text to remove/d' >> newfile

для обработки уже обработанного текста, в этом случае удалите больше строк из того, что было удалено

cat filename | sed '/text to remove/d' | sed '/remove this too/d' | more

в | more будет отображать текст кусками по одной странице за раз.

cat filename | grep -v "pattern" > filename.1
mv filename.1 filename

Вы можете использовать старые добрые edчтобы отредактировать файл аналогично ответу, который используетex. Большая разница в этом случае заключается в том, чтоed принимает свои команды через стандартный ввод, а не как аргументы командной строки, такие как exможет. При использовании его в сценарии, обычно это делается с помощьюprintf передать ему команды:

printf "%s\n" "g/pattern/d" w | ed -s filename

или с наследником:

ed -s filename <<EOF
g/pattern/d
w
EOF

Это решение предназначено для выполнения одной и той же операции с несколькими файлами.

      for file in *.txt; do grep -v "Matching Text" $file > temp_file.txt; mv temp_file.txt $file; done
Другие вопросы по тегам