Как мне использовать sed для удаления всех строк в текстовом файле, содержащих определенную строку?
Как удалить из текстового файла все строки, содержащие определенную строку?
Ответы (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
sed '/pattern to match/d' ./infile > ./newfile
, либо если вы хотите выполнить редактирование на месте, вы можете добавить флаг -i
в sed, как в sed -i '/pattern to match/d' ./infile
. Обратите внимание, что флаг -i
требует GNU sed и не переносится
- person SiegeX; 23.03.2011
sed -i.backup '/pattern to match/d' ./infile
) Это помогло мне внести правки на месте.
- person avelis; 01.02.2013
sed
, к файлам, версия которых не контролируется.
- person MatrixFrog; 28.02.2013
sed -i '' '/pattern/d' ./infile
.
- person geerlingguy; 02.10.2013
-i 'bak'
, либо -i.bak
- person SiegeX; 04.10.2013
sed
для OSX. Надеюсь, этот обновленный ответ будет общим для обоих; он определенно работает с GNU sed
4.2.2
- person SiegeX; 21.10.2015
sed -i.bak "/str/d" ./infile
удаляет весь мой файл.
- person chovy; 16.03.2016
sed -i.bak "\#$pattern_variable_containing_slashes#d" ./infile
- person Eric; 17.03.2016
sed -i -e '/pattern/d' files..
. Причина, по которой требуется дополнительный параметр, заключается в том, что -i
примет шаблон как параметр.
- person akostadinov; 06.04.2016
sed '/pattern to match/d' ./infile > temp && mv temp infile
- person Rahul Murmuria; 17.05.2016
sed -i
, но НЕ распечатать вывод в стандартном формате?
- person carton.swing; 22.05.2017
-i
не должен печатать в стандартный вывод по самой своей природе
- person SiegeX; 22.05.2017
gsed
с MacPorts с sudo port install gsed
.
- person Patrick Sanan; 27.05.2019
sed -i '\#cd /home$#d' myfile
- person Kristof; 16.07.2019
sed -i '0,/pattern to match/d' ./infile
, но мне кажется, что теряются все строки до и включая (первую?) Совпадающую строку.
- person AstroFloyd; 08.07.2020
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
sed
имеет другое поведение, это только greps! это должно быть что-то вроде sed -n -i '/pattern/!p' file
.
- person caesarsol; 28.03.2014
grep -v "pattern" file > temp; mv temp file
Это может относиться к некоторым другим примерам в зависимости от возвращаемого значения.
- person Chris Maes; 20.06.2014
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
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 раза больше времени.
sed '/pattern/d' filename > filename2; mv filename2 filename
- person Pete; 08.04.2014
Самый простой способ сделать это с помощью GNU sed
:
sed --in-place '/some string here/d' yourfile
-r
(или -E
, в зависимости от вашей версии). Это позволяет использовать метасимволы регулярных выражений +
, ?
, {...}
и (...)
.
- person rjh; 17.09.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 и могут быть недоступны в других операционных системах.
man ex
, он дает мне человека для vim
, кажется, ex
является частью vim ... если я правильно понял, это означает, что синтаксис шаблона для match
- vimregex.com, который похож, но отличается от вариантов POSIX и PCRE?
- person Anentropic; 15.11.2015
:g
является POSIX-совместимой командой с некоторыми небольшие различия. Я предполагаю, что PCRE был основан на нем.
- person kenorb; 07.01.2016
Я боролся с этим на Mac. Кроме того, мне нужно было сделать это с помощью замены переменных.
Итак, я использовал:
sed -i '' "/$pattern/d" $file
где $file
- это файл, из которого необходимо удалить, а $pattern
- шаблон, который необходимо сопоставить для удаления.
Я выбрал ''
из этого комментария.
Здесь следует отметить использование двойных кавычек в "/$pattern/d"
. Переменная не будет работать, если мы используем одинарные кавычки.
sed
требует параметра после -i
, поэтому, если вам не нужна резервная копия, вам все равно придется добавить пустую строку: -i ''
- person wisbucky; 12.01.2017
sed -i "/$pattern/d" $file
. Спасибо за ваш ответ.
- person Ashwaq; 03.07.2019
Вы также можете использовать это:
grep -v 'pattern' filename
Здесь -v
будет печатать только отличный от вашего шаблона (что означает обратное совпадение).
Я сделал небольшой тест с файлом, который содержит примерно 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
Чтобы получить результат, похожий на результат с grep
, вы можете сделать это:
echo "$(grep -v "pattern" filename)" >filename
bash
или аналогичной (не tcsh
).
- person esmit; 24.06.2015
САС:
AWK:
GREP:
perl -i -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3
Первая команда редактирует файл (ы) на месте (-i).
Вторая команда делает то же самое, но сохраняет копию или резервную копию исходного файла (ов), добавляя .bk к именам файлов (.bk можно изменить на что угодно).
На всякий случай, если кто-то захочет сделать это для точных совпадений строк, вы можете использовать флаг -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
-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.
показать обработанный текст в консоли
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
будет отображать текст частями по одной странице за раз.
Вы можете использовать старый добрый ed
для редактирования файла аналогично ответу, в котором используется ex
. Большая разница в этом случае состоит в том, что ed
принимает свои команды через стандартный ввод, а не как аргументы командной строки, такие как ex
. При использовании этого параметра в сценарии обычно используется printf
для передачи ему команд:
printf "%s\n" "g/pattern/d" w | ed -s filename
или с наследником:
ed -s filename <<EOF
g/pattern/d
w
EOF
Как ни странно, принятый ответ на самом деле не дает прямого ответа на вопрос. Вопрос касается использования 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"
с вариациями, описанными в другом месте на этой странице.
Удалить строки из всех файлов, соответствующих совпадению
grep -rl 'text_to_search' . | xargs sed -i '/text_to_search/d'