2301

How would I use sed to delete all lines in a text file that contain a specific string?

ivanleoncz
  • 9,070
  • 7
  • 57
  • 49
A Clockwork Orange
  • 23,913
  • 7
  • 25
  • 28

21 Answers21

3480

To remove the line and print the output to standard out:

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

To directly modify the file – does not work with BSD sed:

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

Same, but for BSD sed (Mac OS X and FreeBSD) – does not work with GNU sed:

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

To directly modify the file (and create a backup) – works with BSD and GNU sed:

sed -i.bak '/pattern to match/d' ./infile
Felix Rabe
  • 4,206
  • 4
  • 25
  • 34
SiegeX
  • 135,741
  • 24
  • 144
  • 154
  • 2
    How do I know what version of sed I have? GNU or non GNU? – A Clockwork Orange Mar 23 '11 at 20:39
  • I dont't know why, but the least command resulted in an empty file :( – marquies Oct 04 '15 at 21:49
  • 1
    With GNU sed 4,2,2, the -i '' doesn't work at all. It then treats the pattern to match as the filename. Just remove the ''. – hookenz Oct 19 '15 at 22:29
  • @Matt Thanks for the update. My original answer did not contain the empty quotes part and the answer was edited by the community because of some incompatibility with the OSX version of `sed`. Hopefully this updated answer will be common for both; it certainly works with GNU `sed` 4.2.2 – SiegeX Oct 20 '15 at 22:46
  • 1
    on ubuntu `sed -i.bak "/str/d" ./infile` deletes my entire file. – chovy Mar 16 '16 at 06:18
  • 6
    Note that if your pattern will contain forward slashes, you can use an alternate pattern delimiter but must then escape the first one, e.g.: `sed -i.bak "\#$pattern_variable_containing_slashes#d" ./infile` – Eric Mar 16 '16 at 21:37
  • With GNU sed 4.5, the statement `sed -i '/DELETE ME/d' tables.list` just deletes the string "DELETE ME" and leaves the rest of the line there. – RonJohn Jan 10 '23 at 17:20
719

There are many other ways to delete lines with specific string besides sed:

AWK

awk '!/pattern/' file > temp && mv temp file

Ruby (1.9+)

ruby -i.bak -ne 'print if not /test/' file

Perl

perl -ni.bak -e "print unless /pattern/" file

Shell (bash 3.2 and later)

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

And of course sed (printing the inverse is faster than actual deletion):

sed -n '/pattern/!p' file
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
kurumi
  • 25,121
  • 5
  • 44
  • 52
  • 4
    how to delete a particular line with a pattern and also the line immediately above it? I have a fine with thousands of such lines in between different data. – oortcloud_domicile Aug 06 '13 at 22:41
  • 1
    On OS/X, the shell variation doesn't preserve leading spaces, but the grep -v variation worked well for me. – Paul Beusterien Feb 03 '14 at 23:31
  • 17
    the `sed` example have a different behaviour, it only greps! it should be something like `sed -n -i '/pattern/!p' file`. – caesarsol Mar 28 '14 at 16:41
  • 11
    The grep version does not work when every line matches the pattern. Better do: `grep -v "pattern" file > temp; mv temp file` This might apply to some of the other examples depending on the return value. – Chris Maes Jun 20 '14 at 14:43
  • 5
    "printing the inverse is faster than actual deletion" - Not on my machine (2012 MacBook Air, OS X 10.13.2). Create file: `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. (For smaller files, the difference is larger.) – jcsahnwaldt Reinstate Monica Jan 22 '18 at 02:11
  • would there be any way to leave the first row of the text file, but then apply the delete for all other rows? (for the AWK option) @Peter Mortensen – ZakS Oct 22 '18 at 09:37
  • @PaulBeusterien If you want to preserve leading and trailing spaces just use `while IFS= read -r line` instead (this behavior has nothing to do with OS/X, this is normal in all POSIX-compliant shells) – Harold Fischer Dec 20 '18 at 22:02
  • Please explain how `sed -n '/pattern/!p' file` is "faster" than `sed '/pattern/d' file` – CervEd Jan 06 '22 at 23:32
331

You can use sed to replace lines in place in a file. However, it seems to be much slower than using grep for the inverse into a second file and then moving the second file over the original.

e.g.

sed -i '/pattern/d' filename      

or

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

The first command takes 3 times longer on my machine anyway.

DomainsFeatured
  • 1,426
  • 1
  • 21
  • 39
slashdottir
  • 7,835
  • 7
  • 55
  • 71
108

The easy way to do it, with GNU sed:

sed --in-place '/some string here/d' yourfile
codeforester
  • 39,467
  • 16
  • 112
  • 140
Kevin Nguyen
  • 1,759
  • 2
  • 16
  • 14
  • 82
    A handy tip for others who stumble on this Q&A thread and are new to shell scripting: Short options are fine for one-time uses on the command line, but long options should be preferred in scripts since they're more readable. – Dennis Jan 12 '15 at 10:45
  • 4
    +1 for the --in-place flag. I need to test that out on permissions protected files. (have to do some user scrubbing.) – Bee Kay May 19 '15 at 21:06
  • 10
    Note that the long option is only available on GNU sed. Mac and BSD users will need to install gsed to do it this way. – Matt May 18 '16 at 14:31
  • 2
    Another tip: if your regex doesn't appear to match, try the `-r` option (or `-E`, depending on your version). This enables the use of regex metacharacters `+`, `?`, `{...}` and `(...)`. – rjh Sep 17 '19 at 18:17
  • This is the correct answer when your disk no have more space and you can't copy the text to another file. This command do what was questioned? – ferreirabraga Dec 26 '19 at 13:39
  • @ferreirabraga no "This option specifies that files are to be edited in-place. GNU sed does this by creating a temporary file and sending output to this file rather than to the standard output." – CervEd Jan 06 '22 at 23:39
46

You may consider using ex (which is a standard Unix command-based editor):

ex +g/match/d -cwq file

where:

  • + executes given Ex command (man ex), same as -c which executes wq (write and quit)
  • g/match/d - Ex command to delete lines with given match, see: Power of g

The above example is a POSIX-compliant method for in-place editing a file as per this post at Unix.SE and POSIX specifications for ex.


The difference with sed is that:

sed is a Stream EDitor, not a file editor.BashFAQ

Unless you enjoy unportable code, I/O overhead and some other bad side effects. So basically some parameters (such as in-place/-i) are non-standard FreeBSD extensions and may not be available on other operating systems.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
kenorb
  • 155,785
  • 88
  • 678
  • 743
  • 5
    that's great... when I do `man ex` it gives me the man for `vim`, it seems `ex` is part of vim... if I understood right that means the pattern syntax for `match` is http://vimregex.com/ which is similar but different to POSIX and PCRE flavours? – Anentropic Nov 15 '15 at 19:50
  • 1
    `:g ` is [POSIX-compliant](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ex.html) command with some [slight differences](http://unix.stackexchange.com/a/253820/21471). I assume PCRE was based on it. – kenorb Jan 07 '16 at 10:24
  • @kenorb "I/O overhead and some other bad side effects" could you elaborate? AFAIK `ex` is using a temp file, just like every other sane tool, besides idk using `dd` – CervEd Jan 06 '22 at 23:47
28

I was struggling with this on Mac. Plus, I needed to do it using variable replacement.

So I used:

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

where $file is the file where deletion is needed and $pattern is the pattern to be matched for deletion.

I picked the '' from this comment.

The thing to note here is use of double quotes in "/$pattern/d". Variable won't work when we use single quotes.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Aniket Sinha
  • 6,001
  • 6
  • 37
  • 50
  • 4
    Mac `sed` requires a parameter after `-i`, so if you don't want a backup, you still have to add an empty string: `-i ''` – wisbucky Jan 12 '17 at 00:51
  • 2
    For shell use `sed -i "/$pattern/d" $file` . Thank you for your answer. – Ashwaq Jul 03 '19 at 07:01
23

You can also use this:

 grep -v 'pattern' filename

Here -v will print only other than your pattern (that means invert match).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bhuvanesh
  • 1,269
  • 1
  • 15
  • 25
18

To get a inplace like result with grep you can do this:

echo "$(grep -v "pattern" filename)" >filename
Jahid
  • 21,542
  • 10
  • 90
  • 108
16

I have made a small benchmark with a file which contains approximately 345 000 lines. The way with grep seems to be around 15 times faster than the sed method in this case.

I have tried both with and without the setting LC_ALL=C, it does not seem change the timings significantly. The search string (CDGA_00004.pdbqt.gz.tar) is somewhere in the middle of the file.

Here are the commands and the timings:

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
  • 634
  • 1
  • 8
  • 16
  • Which platform are you on? Which versions of sed/perl/grep do you use? – hagello Feb 21 '18 at 06:01
  • The platform I use is Linux (Gentoo). The sed version is GNU sed v 4.2.2, the perl version perl 5 (I cant tell which revision I used at the time of the test), and grep (GNU) is version 3.0. – Jadzia Feb 21 '18 at 11:56
14

Delete lines from all files that match the match

grep -rl 'text_to_search' . | xargs sed -i '/text_to_search/d'
djperalta
  • 363
  • 3
  • 4
10

SED:

AWK:

GREP:

Giacomo1968
  • 25,759
  • 11
  • 71
  • 103
Oleg Mazko
  • 1,720
  • 15
  • 10
6
perl -i    -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3

The first command edits the file(s) inplace (-i).

The second command does the same thing but keeps a copy or backup of the original file(s) by adding .bk to the file names (.bk can be changed to anything).

Kjetil S.
  • 3,468
  • 20
  • 22
6

You can also delete a range of lines in a file. For example to delete stored procedures in a SQL file.

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

This will remove all lines between CREATE PROCEDURE and END ;.

I have cleaned up many sql files withe this sed command.

GordyCA
  • 71
  • 2
  • 6
4

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

Shizzmo
  • 16,231
  • 3
  • 23
  • 15
4

I found most of the answers not useful for me, If you use vim I found this very easy and straightforward:

:g/<pattern>/d

Source

NicolasElPapu
  • 1,612
  • 2
  • 11
  • 26
  • if your comfortable with `vim` as opposed to `sed` you can use `ex` https://stackoverflow.com/a/33186317 beware that it's slower. What's nice about `vim` is you can `\v` to avoid backslashitis – CervEd Jan 06 '22 at 23:52
3

Just in case someone wants to do it for exact matches of strings, you can use the -w flag in grep - w for whole. That is, for example if you want to delete the lines that have number 11, but keep the lines with number 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

It also works with the -f flag if you want to exclude several exact patterns at once. If "blacklist" is a file with several patterns on each line that you want to delete from "file":

grep -w -v -f blacklist file
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
FatihSarigol
  • 647
  • 7
  • 14
  • 1
    A bit misleading. `-w, --word-regexp Select only those lines containing matches that form whole words.` vs. `-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 $.` – Sai Oct 23 '17 at 13:34
3

to show the treated text in console

cat filename | sed '/text to remove/d' 

to save treated text into a file

cat filename | sed '/text to remove/d' > newfile

to append treated text info an existing file

cat filename | sed '/text to remove/d' >> newfile

to treat already treated text, in this case remove more lines of what has been removed

cat filename | sed '/text to remove/d' | sed '/remove this too/d' | more

the | more will show text in chunks of one page at a time.

nassim
  • 388
  • 3
  • 9
  • 1
    With -i you can edit the file in place: `sed -i '/text to remove/d'` filename is the same as cat `filename | sed '/text to remove/d'` – Martin Krung Jan 28 '23 at 12:49
3

Curiously enough, the accepted answer does not actually answer the question directly. The question asks about using sed to replace a string, but the answer seems to presuppose knowledge of how to convert an arbitrary string into a regex.

Many programming language libraries have a function to perform such a transformation, e.g.

python: re.escape(STRING)
ruby: Regexp.escape(STRING)
java:  Pattern.quote(STRING)

But how to do it on the command line?

Since this is a sed-oriented question, one approach would be to use sed itself:

sed 's/\([\[/({.*+^$?]\)/\\\1/g'

So given an arbitrary string $STRING we could write something like:

re=$(sed 's/\([\[({.*+^$?]\)/\\\1/g' <<< "$STRING")
sed "/$re/d" FILE

or as a one-liner:

 sed "/$(sed 's/\([\[/({.*+^$?]\)/\\\1/g' <<< "$STRING")/d" 

with variations as described elsewhere on this page.

peak
  • 105,803
  • 17
  • 152
  • 177
2
cat filename | grep -v "pattern" > filename.1
mv filename.1 filename
Andrey Izman
  • 1,807
  • 1
  • 24
  • 27
1

You can use good old ed to edit a file in a similar fashion to the answer that uses ex. The big difference in this case is that ed takes its commands via standard input, not as command line arguments like ex can. When using it in a script, the usual way to accomodate this is to use printf to pipe commands to it:

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

or with a heredoc:

ed -s filename <<EOF
g/pattern/d
w
EOF
Shawn
  • 47,241
  • 3
  • 26
  • 60
1

This solution is for doing the same operation on multiple file.

for file in *.txt; do grep -v "Matching Text" $file > temp_file.txt; mv temp_file.txt $file; done
Shaik Ahmad
  • 449
  • 1
  • 3
  • 11