How can I delete specific lines using awk/sed base

2019-08-12 14:26发布

问题:

How can I delete a specific lines from a file based on line numbers that are contained in another file? I know how to delete specific lines by just providing them on the command line, but I do not know how to delete specific lines based on lines numbers that are contained in another file. The file containing the line numbers is in the following format:

15768
15775
15777
15782
15784
15789
15791
15798
15800
15807
15809
15815
15817
15824
15826

There are 2073 lines total that I need to remove. I've tried searching around for how to do this although I was not able to an example similar to this.

Thanks for your help.

回答1:

Assuming the line numbers to be deleted are in a file to-be-deleted and the data is in big-data-file, then, using Bash process substitution:

 sed -f <(sed 's/$/d/' to-be-deleted) big-data-file > smaller-data-file

The inner sed 's/$/d' command converts the line numbers into sed delete operations. The outer sed commands reads the delete commands and applies the operations to the big data file.



回答2:

Using awk:

awk 'FNR==NR{a[$0];next} !(FNR in a)' f1 f2


回答3:

ed is the standard editor.

Here's a possibility to drive ed to do your edit (in place):

#!/bin/bash

ed -s file < <(
    while read line; do
        [[ $line =~ ^[[:digit:]]+$ ]] || continue
        printf "%d d\n" "$line"
    done < lines
    echo "wq"
)

this will open the file file with ed, read the file lines that contains the line numbers, check that each read line is indeed a number, then give to ed the command to delete that number, and when all is done ask ed to write and quit wq.

You might want to replace the [[ $line =~ ^[[:digit:]]+$ ]] || continue line by:

[[ $line =~ ^[[:digit:]]+$ ]] || { printf >&2 "*** WARNING: Line %d not deleted\n" "$line"; continue; }

so as to be warned when invalid lines are present in the file lines.


Make sure you read glenn jackmann's comment:

I've heard some older implementations of ed do not accept wq as a single command: printf "%s\n" w q

YMMV.