Удалить строки в текстовом файле, которые содержат определенную строку
Как бы я использовал 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