I want to delete one or more specific line numbers from a file. How would I do this using sed?
-
1Can you give a more specific example of what you want? How will you decide which lines to remove? – Mark Byers Jan 21 '10 at 20:14
-
Maybe see also https://stackoverflow.com/questions/13272717/inner-join-on-two-text-files and just applyeit in reverse (print if key not in associative array). – tripleee Apr 10 '18 at 18:12
8 Answers
If you want to delete lines from 5 through 10 and line 12th:
sed -e '5,10d;12d' file
This will print the results to the screen. If you want to save the results to the same file:
sed -i.bak -e '5,10d;12d' file
This will store the unmodified file as file.bak
, and delete the given lines.
Note: Line numbers start at 1. The first line of the file is 1, not 0.

- 1,017
- 12
- 21

- 322,767
- 57
- 360
- 340
-
39Not all unixes have gnu sed with "-i". Don't make the mistake of falling back to "sed cmd file > file", which will wipe out your file. – pra Jan 22 '10 at 06:53
-
6
-
18
-
1@BrianCampbell What should i do to delete only a particular line ?? – Kanagavelu Sugumar Apr 24 '14 at 10:56
-
19@KanagaveluSugumar `sed -e '5d' file`. The syntax is `
`; where `` can be either a single line like `5` or a range of lines like `5,10`, and the command `d` deletes the given line or lines. The addresses can also be regular expressions, or the dollar sign `$` indicating the last line of the file. – Brian Campbell Apr 24 '14 at 14:30 -
4Note that the lines from the 5th to 10th are all inclusive. – Herpes Free Engineer Nov 06 '17 at 13:03
-
I am trying to do this using a bash script where I calculate the lines to be deleted dynamically and it is stored in a variable. The number of lines to delete is stored in variable $rows_per_file, but when I add d to it, of course it would fail. Any suggestions on how I can implement this so the d is treated separately than concatenating it to the variable. "sed -i -e 2,$rows_per_filed $2" – Varun Verma Nov 30 '18 at 23:08
-
@BrianCampbell How could I delete for example only the second element of a certain line and not the entire line? – user140259 Dec 14 '20 at 13:13
-
The question of @wearetheworld is not there, so it must have been: Dear Brian, what is the command to start from line 5 including up to the end deleting the content? Greetings, wearethworld – Timo Jul 12 '21 at 19:06
-
Why did not the `sed` people use `-` as a from-to-line-separator, but `,`? – Timo Jul 12 '21 at 19:10
-
You can delete a particular single line with its line number by
sed -i '33d' file
This will delete the line on 33 line number and save the updated file.

- 6,401
- 5
- 37
- 59

- 5,079
- 2
- 17
- 12
-
2In my case "sed" removed a wrong line. So I use this approach: `sed -i '0,/
/{/ – Eduardo Lucio Oct 03 '18 at 22:45/d;}' ' '`. Thanks! -
2Same here, I wrote a loop and strangely some files lost the correct line but some files lost one other line too, have no clue what went wrong. (GNU/Linux bash4.2) awk command below worked fine in loop – FatihSarigol Oct 05 '18 at 08:28
-
1Be really careful to use sort -r if you are deleting from a list of lines, otherwise your first sed will change the line numbers of everything else!... – Konchog Oct 30 '18 at 11:50
-
3To comments about wrong lines being deleted within a loop : be sure to start with the largest line number, otherwise each deleted line will offset the line numbering… – Skippy le Grand Gourou Jun 03 '19 at 12:41
-
1On my system, when processing large files, `sed` appears an order of magnitude slower than a simple combination of `head` and `tail`: here's an example of the faster way (without in-place mode): `delete-line() { local filename="$1"; local lineNum="$2"; head -n $((lineNum-1)) "$filename"; tail +$((lineNum+1)) "$filename"; }` – Ruslan Aug 16 '20 at 08:13
and awk as well
awk 'NR!~/^(5|10|25)$/' file

- 327,991
- 56
- 259
- 343
-
3NB: That awk line worked more reliably for me than the sed variant (between OS-X and Ubuntu Linux) – Jay Taylor Feb 23 '12 at 19:13
-
4Note that this doesn't delete anything in the file. It just prints the file without these lines to stdout. So you also need to redirect the output to a temp file, and then move the temp file to replace the original. – mivk Jun 05 '15 at 09:00
$ cat foo
1
2
3
4
5
$ sed -e '2d;4d' foo
1
3
5
$

- 45,290
- 8
- 103
- 119
-
I like this answer because it also shows that sed counts lines starting from 1 (it could have been 0). – WindChimes Mar 29 '23 at 03:32
This is very often a symptom of an antipattern. The tool which produced the line numbers may well be replaced with one which deletes the lines right away. For example;
grep -nh error logfile | cut -d: -f1 | deletelines logfile
(where deletelines
is the utility you are imagining you need) is the same as
grep -v error logfile
Having said that, if you are in a situation where you genuinely need to perform this task, you can generate a simple sed
script from the file of line numbers. Humorously (but perhaps slightly confusingly) you can do this with sed
.
sed 's%$%d%' linenumbers
This accepts a file of line numbers, one per line, and produces, on standard output, the same line numbers with d
appended after each. This is a valid sed
script, which we can save to a file, or (on some platforms) pipe to another sed
instance:
sed 's%$%d%' linenumbers | sed -f - logfile
On some platforms, sed -f
does not understand the option argument -
to mean standard input, so you have to redirect the script to a temporary file, and clean it up when you are done, or maybe replace the lone dash with /dev/stdin
or /proc/$pid/fd/1
if your OS (or shell) has that.
As always, you can add -i
before the -f
option to have sed
edit the target file in place, instead of producing the result on standard output. On *BSDish platforms (including OSX) you need to supply an explicit argument to -i
as well; a common idiom is to supply an empty argument; -i ''
.

- 175,061
- 34
- 275
- 318
-
I don't quite agree with "symptom of an antipattern". Markup-based file types (e.g. XML or JSON) require specific lines at the end in order to be valid files. In that case, it's often the most reasonable approach to remove those lines, put into the file what you want to be added and then re-add those lines, because putting the lines in between straight away can be much more effort, and goes against the potential desire to avoid extra tools like sed as much as you can. – Egor Hans Nov 12 '17 at 12:02
-
I don't quite understand what sort of scenario you are imagining. There *are* scenarios where this is a legitimate approach but the vast majority of cases I have seen are newbies who do more or less exactly what my first example demonstrates. (Perhaps they come from some really low-level language and are used to dividing their problem way past the molecular level, because you have to in asm or C.) – tripleee Apr 10 '18 at 18:07
-
1Removing stuff by line number from XML or JSON sounds *extermely* brittle, if not outright dangerous. – tripleee Apr 10 '18 at 18:08
-
What I basically mean by that, is that as the creator of such a file, you know what has to be at the end of the document (i.e. the set of closing braces/square brackets in the last few lines for JSON, or the exact closing tags for XML). Being aware of that, the most simple approach to extend such a document is 1) remove the last few lines, 2) add the new content, 3) re-add the last few lines. This way, the document can be valid both before and after it has been extended, without needing to find a way of adding lines mid-document. – Egor Hans Apr 20 '18 at 14:44
-
@EgorHans You still usually don't know or care what line *numbers* those lines occupy. Removing them via a regex is more likely to be correct as well as more efficient; though most of the time, you should actually use a tool which can handle the intricacies of your structured format correctly (`jq` is popular for JSON; `xmlstarlet`, `xsltproc`, `xmllint`, `xpath` etc are available for XML). – tripleee May 05 '18 at 15:32
-
Usually they're `file_line_amount - n` through `file_line_amount`, where n is known from the context-based structure specs (e.g. nesting of the tag content is being added to can, in many scenarios, be straightly or almost straightly be used as n). I agree though, that regex-based approaches or dedicated tools are better simply for readability and good practice. – Egor Hans May 06 '18 at 15:07
-
1So far this is the only answer with an appropriate solution for a large number of lines (i.e. provided by a file). And the foreword makes sense too. It deserves more upvotes. BTW, if you want to *print* lines rather than delete them, use `p` instead of `d`, along with option `-n` (it won't work without `-n`, and `!d` won't work either). – Skippy le Grand Gourou Jun 03 '19 at 13:01
-
I don't see that this is necessarily an antipattern. For instance, ssh just told me there was an outdated RSA key on line 18 of .ssh/known_hosts. So therefore I want to delete line 18 of that file. – joachim Jul 03 '23 at 17:15
-
@joachim That is indeed entirely distinct from the actual antipattern, which basically amounts to "I want to loop over all the lines so I can _then_ loop over them again and delete some of them, even though the tool I am using is perfectly capable of identifying and deleting those lines in a single pass." – tripleee Jul 03 '23 at 17:18
-
1(Obviously, `sed -i 18d .ssh/known_hosts`, or `-i '' 18d` if you're on MacOS or another BSD-derived system.) – tripleee Jul 03 '23 at 17:20
I would like to propose a generalization with awk.
When the file is made by blocks of a fixed size and the lines to delete are repeated for each block, awk can work fine in such a way
awk '{nl=((NR-1)%2000)+1; if ( (nl<714) || ((nl>1025)&&(nl<1029)) ) print $0}'
OriginFile.dat > MyOutputCuttedFile.dat
In this example the size for the block is 2000 and I want to print the lines [1..713] and [1026..1029].
NR
is the variable used by awk to store the current line number.%
gives the remainder (or modulus) of the division of two integers;nl=((NR-1)%BLOCKSIZE)+1
Here we write in the variable nl the line number inside the current block. (see below)||
and&&
are the logical operator OR and AND.print $0
writes the full line
Why ((NR-1)%BLOCKSIZE)+1:
(NR-1) We need a shift of one because 1%3=1, 2%3=2, but 3%3=0.
+1 We add again 1 because we want to restore the desired order.
+-----+------+----------+------------+
| NR | NR%3 | (NR-1)%3 | (NR-1)%3+1 |
+-----+------+----------+------------+
| 1 | 1 | 0 | 1 |
| 2 | 2 | 1 | 2 |
| 3 | 0 | 2 | 3 |
| 4 | 1 | 0 | 1 |
+-----+------+----------+------------+

- 2,470
- 27
- 36
cat -b /etc/passwd | sed -E 's/^( )+(<line_number>)(\t)(.*)/--removed---/g;s/^( )+([0-9]+)(\t)//g'
cat -b
-> print lines with numbers
s/^( )+(<line_number>)(\t)(.*)//g
-> replace line number to null (remove line)
s/^( )+([0-9]+)(\t)//g
#remove numbers the cat
printed

- 11
- 3