Oscar
Oscar

Reputation: 9

How to filter information depending on a parameter in bash

I want to filter the output of a command in a specific way. Let's suppose the following output:

==== Foo ====
Line to filter 1
Line to filter 2
Line to filter 3
Line to filter 4
Line to filter 5
==== Bar ====
Line to filter 6
Line to filter 7
Line to filter 8
Line to filter 9
Line to filter 10

What I'm trying to do is to filter with one command the Lines to filter 1-5 depending if the "parameter" in the command is Foo or Bar. For example:

command | grep '... Foo ...', output:

Line to filter 1
Line to filter 2
Line to filter 3
Line to filter 4
Line to filter 5

command | grep '... Bar ...', output:

Line to filter 6
Line to filter 7
Line to filter 8
Line to filter 9
Line to filter 10

Is there a possible way to do it? Thank you!

Upvotes: 1

Views: 122

Answers (1)

ghoti
ghoti

Reputation: 46826

So many ways you could do this. Using awk:

awk -v s="Foo" '/^=/&&$2!=s { p=0 } p==1; /^=/&&$2==s { p=1 }' input.txt

This uses a marker, p, that gets toggled based on the content of any header line it finds.

A second approach (brazenly stolen from from 123's deleted answer, which I liked) is much shorter:

awk -v s="$var" '/^=/{p=$0~s;next} p'

This awk script has two expressions - the first sets p to the boolean result of the evaluation $0~s, and the second prints the line if p is true. p only changes on header lines. I can't think of a shorter way to express this task in awk.

An approach in sed might be:

sed -ne '/^==== Foo/,/^====/{;/^====/d;p;}' input.txt

But you can't pass variables in to sed, so you'd be rewriting your actual script for this, which is a little uglier. If you wanted to sanitize your input in bash, you could do so using parameter expansion. For example, you could strip any non-alphanumeric characters, if you're pretty sure that's what you expect to see in titles:

s="##Fo@o! "
sed -ne "/^==== ${s//[^[:alnum:]]/}/,/^====/{;/^====/d;p;}" input.txt

Of course, sed and awk are available from bash, but they don't represent bash scripting. This could be done in bash alone, too:

s="Foo"; p=false
while read line; do 
  [[ $line =~ ^==== ]] && p=false
  $p && echo "$line"
  [[ $line =~ ^====\ $s ]] && p=true
done < input.txt

This follows the example of the awk script above, setting a boolean which gets toggled depending on what header we see.

Upvotes: 1

Related Questions