Markus
Markus

Reputation: 3627

Reading a subset of the lines in a text file, with bash

I have a file

line a - this is line a
line b - this is line b
line c - this is line c
line d - this is line d
line e - this is line e

The question is: How can I output the lines starting from "line b" till "line d" using bash commands? I mean, to obtain:

"line b - this is line b
 line c - this is line c
 line d - this is line d"

Upvotes: 3

Views: 4079

Answers (6)

ghostdog74
ghostdog74

Reputation: 342313

sed -n '/line b/,/line d/p' file

Upvotes: 5

notnoop
notnoop

Reputation: 59299

Another approach which depends on what you mean:

pcregrep -m 'line b - this is line b
 line c - this is line c
 line d - this is line d' file

Upvotes: 0

ghostdog74
ghostdog74

Reputation: 342313

for your set of sample data:

awk '/line b/,/line d/' file

Or

awk '/line d/{f=0;print}/line b/{f=1}f' file

Upvotes: 3

anon
anon

Reputation:

You can do it using bash alone, though I agree with Pax that using other tools is probably a better solution. Here's a bash-only solution:

while read line
do
    t=${line#line b}
    if test "$t" != "$line"
    then
        echo $line
        while read line
        do
            echo $line
            t=${line#line d}
            if test "$t" != "$line"
            then
                exit 0
            fi
        done
    fi
done

Upvotes: 1

Paolo Capriotti
Paolo Capriotti

Reputation: 4072

Your example is not enough to infer what you want in the general case, but assuming you want to remove the first and last line, you can simply use

tail -n+2 $filename | head -n-1

Here tail -n+2 prints all the lines starting from the second, and head -n-1 prints all the lines except the last.

Upvotes: 5

paxdiablo
paxdiablo

Reputation: 881193

If by bash, you mean actually bash alone, I can't help you. You really should be using the right tools for the job. If you mean standard UNIX utilities that you can call from bash, I would be using awk for that.

echo 'line a - this is line a
line b - this is line b
line c - this is line c
line d - this is line d
line e - this is line e' | awk '
    BEGIN {e=0}
    /^line b/ {e=1}
    /^line d/ {if (e==1) {print;exit}}
    {if (e==1) print}
'

This outputs:

line b - this is line b
line c - this is line c
line d - this is line d

The way it works is simple.

  • e is the echo flag, initially set to false (0).
  • when you find line b, set echo to true (1) - don't print yet. That will be handled by the last bullet point below.
  • when you find line d and echo is on, print it and exit.
  • when echo is on, print the line (this includes line b).

I've made an assumption here that you don't want to exit on a line d unless you're already echoing. If that's wrong, move the exit outside of the if statement for line d:

    /^line d/ {if (e==1) print;exit}

Then, if you get a line d before your line b, it will just exit without echoing anything.

The "/^line X/"-type clauses can be made very powerful to match pretty well anything you can throw at it.

Upvotes: 2

Related Questions