Как удалить из текстового файла все строки, содержащие определенную строку?

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


person A Clockwork Orange    schedule 23.03.2011    source источник


Ответы (18)


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

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

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

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

То же самое, но для BSD sed (Mac OS X и FreeBSD) - не работает с GNU sed:

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

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

sed -i.bak '/pattern to match/d' ./infile
person SiegeX    schedule 23.03.2011
comment
Спасибо, но похоже, что он не удаляет его из файла, а просто распечатывает содержимое текстового файла без этой строки. - person A Clockwork Orange; 23.03.2011
comment
@A Clockwork: да, вам нужно перенаправить вывод либо в новый файл с чем-то вроде sed '/pattern to match/d' ./infile > ./newfile, либо если вы хотите выполнить редактирование на месте, вы можете добавить флаг -i в sed, как в sed -i '/pattern to match/d' ./infile. Обратите внимание, что флаг -i требует GNU sed и не переносится - person SiegeX; 23.03.2011
comment
Как узнать, какая у меня версия sed? GNU или не GNU? - person A Clockwork Orange; 23.03.2011
comment
Для некоторых ароматов sed; Флаг -i sed требует предоставления расширения. (например, sed -i.backup '/pattern to match/d' ./infile) Это помогло мне внести правки на месте. - person avelis; 01.02.2013
comment
@SiegeX Еще лучше не применять такие команды, как sed, к файлам, версия которых не контролируется. - person MatrixFrog; 28.02.2013
comment
Еще одно замечание для пользователей Mac OS X: по какой-то причине флаг -i требует передачи аргумента, даже если это просто пустая строка, например sed -i '' '/pattern/d' ./infile. - person geerlingguy; 02.10.2013
comment
@geerlingguy см. комментарий Авелиса выше. У меня нет Mac (пока), но я собираюсь сделать обоснованное предположение, что вы можете делать либо -i 'bak', либо -i.bak - person SiegeX; 04.10.2013
comment
Не знаю почему, но наименьшая команда привела к пустому файлу :( - person marquies; 05.10.2015
comment
В GNU sed 4,2,2 -i '' вообще не работает. Затем он обрабатывает шаблон для сопоставления как имя файла. Просто удалите "". - person hookenz; 20.10.2015
comment
@Matt Спасибо за обновление. В моем исходном ответе не было пустых кавычек, и ответ был отредактирован сообществом из-за некоторой несовместимости с версией sed для OSX. Надеюсь, этот обновленный ответ будет общим для обоих; он определенно работает с GNU sed 4.2.2 - person SiegeX; 21.10.2015
comment
на ubuntu sed -i.bak "/str/d" ./infile удаляет весь мой файл. - person chovy; 16.03.2016
comment
Обратите внимание, что если ваш шаблон будет содержать косые черты, вы можете использовать альтернативный разделитель шаблона, но затем должны экранировать первый, например: sed -i.bak "\#$pattern_variable_containing_slashes#d" ./infile - person Eric; 17.03.2016
comment
@geerlingguy, лучше сделать sed -i -e '/pattern/d' files... Причина, по которой требуется дополнительный параметр, заключается в том, что -i примет шаблон как параметр. - person akostadinov; 06.04.2016
comment
Для обратной записи в файл, похоже, требуется промежуточный временный файл: sed '/pattern to match/d' ./infile > temp && mv temp infile - person Rahul Murmuria; 17.05.2016
comment
@RahulMurmuria да, см. 2-й комментарий вверху этого ответа - person SiegeX; 17.05.2016
comment
Если я хочу найти образец, который заканчивается на «E1» (а не на «E11» или «E12»), что мне делать? - person AishwaryaKulkarni; 19.09.2016
comment
@AishwaryaKulkarni Вы должны привязать свое совпадение к '$', как в '/ шаблон, заканчивающийся на E1 $ /' - person SiegeX; 19.09.2016
comment
Так как файл sed '/ E1 $ / d'? - person AishwaryaKulkarni; 19.09.2016
comment
как я могу использовать sed -i, но НЕ распечатать вывод в стандартном формате? - person carton.swing; 22.05.2017
comment
@ carton.swing -i не должен печатать в стандартный вывод по самой своей природе - person SiegeX; 22.05.2017
comment
Обратите внимание, что "шаблон для соответствия" чувствителен к регистру. - person rolfedh; 14.12.2017
comment
Примечание для людей, которые хотят редактировать ОГРОМНЫЕ файлы: sed записывает временный файл. Это не совсем то место. Если у вас недостаточно места на диске, вам а) не хватит места на диске и б) придется вручную удалить временный файл. - person SeamusJ; 26.10.2018
comment
Для Mac OS X новая строка будет добавляться к файлам без каких-либо совпадений, это совсем не хорошо! - person machinarium; 05.03.2019
comment
Другой вариант в OS X (который включает BSD sed) - установить GNU sed, например, получить gsed с MacPorts с sudo port install gsed. - person Patrick Sanan; 27.05.2019
comment
Дополнительная информация в комментариях должна быть добавлена ​​к ответу при редактировании. Благодаря комментариям Эрика и @SiegeX мне удалось удалить строку cd / home, не удаляя cd / home / workdir. Комбинированная команда была: sed -i '\#cd /home$#d' myfile - person Kristof; 16.07.2019
comment
Есть ли способ удалить только первое вхождение соответствующей строки и сохранить остальную часть файла нетронутой? Я пробовал sed -i '0,/pattern to match/d' ./infile, но мне кажется, что теряются все строки до и включая (первую?) Совпадающую строку. - person AstroFloyd; 08.07.2020
comment
@AstroFloyd с GNU sed sed -i '0,/pattern to match/{/pattern to match/d} ./infile - person SiegeX; 26.07.2020

Есть много других способов удалить строки с определенной строкой, кроме 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

Оболочка (bash 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
person kurumi    schedule 23.03.2011
comment
как удалить конкретную строку с шаблоном, а также строку непосредственно над ней? У меня штраф с тысячами таких строк между разными данными. - person oortcloud_domicile; 07.08.2013
comment
В OS / X вариант оболочки не сохраняет ведущие пробелы, но вариант grep -v у меня хорошо сработал. - person Paul Beusterien; 04.02.2014
comment
пример sed имеет другое поведение, это только greps! это должно быть что-то вроде sed -n -i '/pattern/!p' file. - person caesarsol; 28.03.2014
comment
Версия grep не работает, если каждая строка соответствует шаблону. Лучше сделать: grep -v "pattern" file > temp; mv temp file Это может относиться к некоторым другим примерам в зависимости от возвращаемого значения. - person Chris Maes; 20.06.2014
comment
печать инверсии выполняется быстрее, чем фактическое удаление - нет на моем компьютере (MacBook Air 2012 года, OS X 10.13.2). Создать файл: seq -f %f 10000000 >foo.txt. sed d: time sed -i '' '/6543210/d' foo.txt real 0m9.294s. sed! p: time sed -i '' -n '/6543210/!p' foo.txt real 0m13.671s. (Для файлов меньшего размера разница больше.) - person jcsahnwaldt Reinstate Monica; 22.01.2018
comment
есть ли способ оставить первую строку текстового файла, но затем применить удаление ко всем остальным строкам? (для варианта AWK) @Peter Mortensen - person ZakS; 22.10.2018
comment
@PaulBeusterien Если вы хотите сохранить начальные и конечные пробелы, просто используйте вместо этого while IFS= read -r line (это поведение не имеет ничего общего с OS / X, это нормально для всех POSIX-совместимых оболочек) - person Harold Fischer; 21.12.2018

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

e.g.

sed -i '/pattern/d' filename      

or

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

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

person slashdottir    schedule 02.11.2012
comment
Проголосуйте и за ваш ответ, просто потому, что вы попробовали сравнить производительность! - person anuragw; 12.04.2013
comment
+1 за возможность перезаписать текущий файл строкой grep. - person Rhyuk; 07.05.2013
comment
по какой-то причине версия sed для mac os (BSD) не принимает имя файла резервной копии нулевой длины, но когда оно указано, оно работает. - person Pikachu; 03.10.2013
comment
Второе решение grep также лучше подходит для больших файлов. - person simoes; 02.01.2014
comment
Мне любопытно, какая была бы разница в производительности, если бы она была sed '/pattern/d' filename > filename2; mv filename2 filename - person Pete; 08.04.2014
comment
(используя ubuntu / usr / share / dict / words) grep и mv: 0.010s | sed на месте: 0.197s | sed и mv: 0,031 с - person ReactiveRaven; 10.02.2015
comment
Как я могу удалить строку, содержащую текст, в ЛЮБОМ файле? Допустим, я нахожусь в / var / www / html / и хочу удалить строку, содержащую hacker.com, в любом файле PHP? - person Asle; 18.04.2016
comment
найти . -тип f -имя * .php | xargs -ifile sed -i '/hacker.com/d' файл - person slashdottir; 02.05.2016
comment
Как удалить строки в каталоге, содержащие определенную строку - person namannimmo; 10.02.2020

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

sed --in-place '/some string here/d' yourfile
person Kevin Nguyen    schedule 02.01.2015
comment
Полезный совет для тех, кто наткнется на эту ветку вопросов и ответов и не знаком с написанием сценариев оболочки: короткие параметры подходят для одноразового использования в командной строке, но длинные параметры должны быть предпочтительнее в сценариях, поскольку они более читабельны. - person Dennis; 12.01.2015
comment
+1 для флага --in-place. Мне нужно проверить это на файлах, защищенных разрешениями. (нужно выполнить некоторую очистку пользователя.) - person Bee Kay; 20.05.2015
comment
Обратите внимание, что длинный вариант доступен только в GNU sed. Пользователям Mac и BSD для этого потребуется установить gsed. - person Matt; 18.05.2016
comment
Еще один совет: если ваше регулярное выражение не соответствует, попробуйте параметр -r (или -E, в зависимости от вашей версии). Это позволяет использовать метасимволы регулярных выражений +, ?, {...} и (...). - person rjh; 17.09.2019
comment
Это правильный ответ, если на вашем диске больше нет места и вы не можете скопировать текст в другой файл. Эта команда делает то, о чем спрашивали? - person ferreirabraga; 26.12.2019

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

ex +g/match/d -cwq file

куда:

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

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


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

sed - это S tream ED itor, а не файловый редактор. BashFAQ

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

person kenorb    schedule 17.10.2015
comment
это здорово ... когда я делаю man ex, он дает мне человека для vim, кажется, ex является частью vim ... если я правильно понял, это означает, что синтаксис шаблона для match - vimregex.com, который похож, но отличается от вариантов POSIX и PCRE? - person Anentropic; 15.11.2015
comment
:g является POSIX-совместимой командой с некоторыми небольшие различия. Я предполагаю, что PCRE был основан на нем. - person kenorb; 07.01.2016

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

Итак, я использовал:

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

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

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

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

person Aniket Sinha    schedule 09.03.2016
comment
Mac sed требует параметра после -i, поэтому, если вам не нужна резервная копия, вам все равно придется добавить пустую строку: -i '' - person wisbucky; 12.01.2017
comment
Для оболочки используйте sed -i "/$pattern/d" $file. Спасибо за ваш ответ. - person Ashwaq; 03.07.2019

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

 grep -v 'pattern' filename

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

person Bhuvanesh    schedule 28.03.2015

Я сделал небольшой тест с файлом, который содержит примерно 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
person Jadzia    schedule 19.03.2017
comment
На какой платформе вы находитесь? Какие версии sed / perl / grep вы используете? - person hagello; 21.02.2018
comment
Я использую платформу Linux (Gentoo). Версия sed - это GNU sed v 4.2.2, версия perl - perl 5 (я не могу сказать, какую ревизию я использовал во время теста), а grep (GNU) - это версия 3.0. - person Jadzia; 21.02.2018

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

echo "$(grep -v "pattern" filename)" >filename
person Jahid    schedule 13.06.2015
comment
Это подходит только для оболочки bash или аналогичной (не tcsh). - person esmit; 24.06.2015


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

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

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

person Kjetil S.    schedule 30.06.2014

На всякий случай, если кто-то захочет сделать это для точных совпадений строк, вы можете использовать флаг -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
person FatihSarigol    schedule 02.03.2017
comment
Немного вводит в заблуждение. -w, --word-regexp Select only those lines containing matches that form whole words. против -x, --line-regexp Select only those matches that exactly match the whole line. For a regular expression pattern, this is like parenthesizing the pattern and then surrounding it with ^ and $. - person Sai; 23.10.2017

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

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

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

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

person GordyCA    schedule 02.09.2020

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

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 будет отображать текст частями по одной странице за раз.

person nassim    schedule 27.02.2020

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

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

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

ed -s filename <<EOF
g/pattern/d
w
EOF
person Shawn    schedule 19.03.2020

Как ни странно, принятый ответ на самом деле не дает прямого ответа на вопрос. Вопрос касается использования 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" 

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

person peak    schedule 23.10.2020

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

grep -rl 'text_to_search' . | xargs sed -i '/text_to_search/d'
person djperalta    schedule 26.02.2021

person    schedule
comment
Вы перезаписываете файл, пока он еще используется. - person Davor Cubranic; 28.06.2018
comment
@DavorCubranic исправлено - person Andrey Izman; 29.06.2018