Удаление строк в текстовом файле, содержащих определенную строку
Как использовать sed для удаления всех строк в текстовом файле, содержащих определенную строку?
14 ответов
чтобы удалить строку и распечатать вывод на стандартный выход:
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 (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
Вы можете использовать sed для замены строк в файл. Однако, похоже, это намного медленнее, чем использование grep для обратного во второй файл, а затем перемещение второго файла по оригиналу.
например
sed -i '/pattern/d' filename
или
grep -v "pattern" filename > filename2; mv filename2 filename
первая команда занимает в 3 раза больше времени на моей машине.
вы можете использовать ex
(который является стандартным Unix-командным редактором):
ex +g/match/d -cwq file
где:
-
+
выполняет данную команду Ex (man ex
), как-c
, который выполняетwq
(запись и выход) -
g/match/d
- Ex команда для удаления строк с заданнымmatch
см.: мощность g
приведенный выше пример является POSIX-совместимым методом для редактирования файла на месте как за это пост в Unix.СЕ и спецификации POSIX для ex
.
разница с sed
это:
sed
это Stream Эдitor, а не редактор файлов.BashFAQ
Если вам не нравится непортящийся код, накладные расходы на ввод-вывод и некоторые другие плохие побочные эффекты. Поэтому в основном некоторые параметры (например, in-place/-i
) являются нестандартные расширения FreeBSD и могут быть недоступны в других операционных системах.
я боролся с этим на Mac. Кроме того, мне нужно было сделать это с помощью замены переменных.
поэтому я использовал:
sed -i '' "/$pattern/d" $file
здесь $file
- это файл, в котором требуется удаление и $pattern
является шаблоном для удаления.
Я выбрал ''
отсюда комментарий.
здесь следует отметить использование двойные кавычки на "/$pattern/d"
. Переменная не будет работать, когда мы используем один двойные кавычки.
чтобы получить inplace как результат с grep
можно сделать так:
echo "$(grep -v "pattern" filename)" >filename
Я сделал небольшой тест с файлом, который содержит около 345 000 строк. Путь с grep
Кажется, примерно в 15 раз быстрее, чем sed
метод в данном случае.
Я пробовал как с настройкой LC_ALL=C, так и без нее, похоже, что тайминги существенно не меняются. Строка поиска (CDGA_00004.pdbqt.ГЗ.смола) где-то в середине файла.
вот команды и тайминги:
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
вы также можете использовать это:
grep -v 'pattern' filename
здесь -v
будет печатать только кроме вашего шаблона (это означает инвертировать совпадение).
perl -i -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3
первая команда редактирует файл(ы) inplace (-i).
вторая команда делает то же самое, но сохраняет копию или резервную копию оригинального файла(ов) путем добавления .БК к именам файлов (.БК можно изменить на что угодно).
на всякий случай, если кто-то хочет сделать это для точного соответствия строк, вы можете использовать -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