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

1790

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

Заводной апельсин
источник

Ответы:

2760

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

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
SiegeX
источник
13
Спасибо, но он, кажется, не удаляет его из файла, а просто распечатывает содержимое текстового файла без этой строки.
Заводной апельсин
115
@ Часовой механизм: да, вам нужно перенаправить вывод либо в новый файл с чем-то вроде, sed '/pattern to match/d' ./infile > ./newfileлибо, если вы хотите выполнить редактирование на месте, тогда вы можете добавить -iфлаг в sed, как в sed -i '/pattern to match/d' ./infile. Обратите внимание, что -iфлаг требует GNU sed и не является переносимым
SiegeX
16
Для некоторого аромата sed; Флаг sed "-i" требовал предоставления расширения. (например sed -i.backup '/pattern to match/d' ./infile) Это помогло мне с правками на месте.
Авелис
9
@SiegeX Еще лучше, не применяйте команды, подобные sedтем, которые не контролируются версиями.
MatrixFrog
84
Еще одно замечание для пользователей Mac OS X: по какой-то причине флаг -i требует передачи аргумента, даже если это просто пустая строка, например sed -i '' '/pattern/d' ./infile.
geerlingguy
631

Есть много других способов удалить строки с определенной строкой, кроме 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
Каруми
источник
4
Как удалить конкретную линию с рисунком, а также линию непосредственно над ним? У меня есть штраф с тысячами таких строк между различными данными.
oortcloud_domicile
1
В OS / X вариант оболочки не сохраняет начальные пробелы, но вариант grep -v мне помог.
Пол Бустериен
13
sedпример имеет различное поведение, он только отбирает! это должно быть что-то вроде sed -n -i '/pattern/!p' file.
Цезарсоль
8
Версия grep не работает, когда каждая строка соответствует шаблону. Лучше сделать: grep -v "pattern" file > temp; mv temp fileэто может относиться к некоторым другим примерам в зависимости от возвращаемого значения.
Крис Мэйс
1
«обратная печать выполняется быстрее, чем фактическое удаление» - не на моем компьютере (2012 MacBook Air, OS X 10.13.2). Создать файл: seq -f %f 10000000 >foo.txt. sed d: time sed -i '' '/6543210/d' foo.txtреальный 0m9.294s. sed! p: time sed -i '' -n '/6543210/!p' foo.txtреальный 0m13.671s. (Для файлов меньшего размера разница больше.)
jcsahnwaldt говорит GoFundMonica
252

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

например

sed -i '/pattern/d' filename      

или

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

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

slashdottir
источник
19
Голосуйте за ваш ответ тоже, просто потому что вы попробовали сравнение производительности!
anuragw
4
+1 за возможность перезаписать текущий файл строкой grep.
Rhyuk
2
Второе решение «Grep» также лучше для больших файлов
Симоэш
3
Мне интересно, какая разница в производительности, если бы это былоsed '/pattern/d' filename > filename2; mv filename2 filename
Пит
9
(используя ubuntu / usr / share / dict / words) grep и mv: 0.010s | сед на месте: 0,197 с | sed и mv: 0,031 с
ReactiveRaven
77

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

sed --in-place '/some string here/d' yourfile
Кевин Нгуен
источник
56
Полезный совет для тех, кто спотыкается в этом потоке вопросов и ответов и плохо знаком с сценариями оболочки: короткие варианты подходят для одноразового использования в командной строке, но длинные сценарии должны быть предпочтительнее в сценариях, поскольку они более читабельны.
Деннис
3
+1 за --in-place флаг. Мне нужно проверить это на разрешениях защищенных файлов. (нужно сделать некоторую пользовательскую чистку.)
Bee Kay
8
Обратите внимание, что опция long доступна только в GNU sed. Пользователи Mac и BSD должны будут установить gsed, чтобы сделать это таким образом.
Мэтт
Другой совет: если ваше регулярное выражение не соответствует, попробуйте -rвариант (или -E, в зависимости от вашей версии). Это позволяет использовать регулярные выражения метасимволов +, ?, {...}и (...).
rjh
Это правильный ответ, когда на вашем диске больше нет места, и вы не можете скопировать текст в другой файл. Эта команда делает то, что было опрошено?
ferreirabraga
38

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

ex +g/match/d -cwq file

где:

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

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


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

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

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

kenorb
источник
5
это здорово ... когда я делаю man exэто дает мне человек за vimэто , кажется , exявляется частью Vim ... если я понял правильно , что означает , что синтаксис шаблона для matchявляется vimregex.com , который похож , но отличается от POSIX и PCRE вкусов?
Anentropic
1
:g является POSIX-совместимой командой с некоторыми небольшими отличиями . Я предполагаю, что PCRE был основан на этом.
Кенорб
16

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

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

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

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

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

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

Аникет Синха
источник
3
Mac sedтребует параметр после -i, поэтому, если вы не хотите создавать резервную копию, вам все равно нужно добавить пустую строку:-i ''
wisbucky
Для использования оболочки sed -i "/$pattern/d" $file. Спасибо за ваш ответ.
Ашвакар
14

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

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

 grep -v 'pattern' filename

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

Bhuvanesh
источник
Как я могу удалить строки в каталоге, которые содержат определенную строку
namannimmo
13

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

echo "$(grep -v "pattern" filename)" >filename
Jahid
источник
4
Это хорошо только для bashоболочки или аналогичной (не tcsh).
Esmit
4
perl -i    -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3

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

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

Кжетил С.
источник
2

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

Shizzmo
источник
2

На всякий случай, если кто-то захочет сделать это для точного соответствия строк, вы можете использовать -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
FatihSarigol
источник
Немного вводит в заблуждение -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 $.
Сай
1
cat filename | grep -v "pattern" > filename.1
mv filename.1 filename
Андрей Изман
источник
Вы перезаписываете файл, пока он еще используется.
Давор Кубраник,
@DavorCubranic исправлено
Андрей Изман
0

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

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покажет текст кусков одной страницы за один раз.

Нассим
источник
0

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

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

или с наследственностью:

ed -s filename <<EOF
g/pattern/d
w
EOF
Шон
источник