1

I have this script where I ask for 4 patterns and then use those in a grep command. That is, I want to see if a line matches any of the patterns.

echo -n "Enter pattern1"
read pat1
echo -n "Enter pattern2"
read pat2
echo -n "Enter pattern3"
read pat3
echo -n "Enter pattern4"
read pat4

cat somefile.txt | grep $pat1 | grep $pat2 | grep $pat3 | grep $pat4 

The problem I'm running into is that if the user doesn't supply one of the patterns (which I want to allow) the grep command doesn't work.

So, is there a way to have grep ignore one of the patterns if it's returned empty?

fedorqui
  • 275,237
  • 103
  • 548
  • 598
berserker
  • 17
  • 2
  • @fedorqu -- I apologize for asking a duplicate question. If it's not painfully obvious by now, I'm very new to this. – berserker Jun 22 '16 at 13:04
  • @berserker do you want to filter with an AND or an OR? piping grep to another grep will filter the first results. Note that if you say `pat=${pat:-""}` will replace empty content with `""` and then `grep "$pat"` it works, since `grep "" file` just returns the full content. – fedorqui Jun 22 '16 at 13:12
  • @fedorqu -- I want to filter by OR. Basically, I'm doing a syslog search and am taking input for src and dst ip as well as src and dst port. I want my search to run with either all 4 inputs or a mix of either of them. – berserker Jun 22 '16 at 13:20
  • berserker then, piping is wrong because it does AND. Check @Camusensei as a good start on how to do this. – fedorqui Jun 22 '16 at 13:22
  • @fedorqu -- You are correct. Sorry for all the confusion -- I'm learning and not articulating my intentions well. My previous comment is incorrect when I said OR. A usage example: I ask the user to provide 4 things (src ip/prt and dst ip/prt). They only give me src ip and dst ip and just skipping over src prt and dst prt. i would want to filter by AND. Does this make sense? – berserker Jun 22 '16 at 13:34
  • @berserker how about the number of patterns, are you sure about 4? or can it be more? less? (less it can be otherwise you would not have asked anything ^^) – Camusensei Jun 22 '16 at 13:36
  • @Camusensei -- It's a max of four. It can definitely be less though. – berserker Jun 22 '16 at 13:37
  • @berserker I edited my answer. Hopefully this will suit your needs :) – Camusensei Jun 22 '16 at 13:54
  • @Camusensei -- Hey, thanks again for your help. I was able to put it together and get it to do what I want. I was wondering if you have the time to explain one line of your answer, namely: pattern="${pattern:+"$pattern && "}/${input//\//\\/}/" Thanks! – berserker Jun 23 '16 at 12:00
  • @berserker You should have commented on my answer instead of the question. In any case, that's [parameter expansion](http://wiki.bash-hackers.org/syntax/pe). I'm escaping slashes and inserting `$pattern` plus the string `&&` if `$pattern` is not empty. – Camusensei Jun 23 '16 at 12:34

1 Answers1

3

Your code has lots of problems:

  • Code duplication
  • Interactive asking for potentially unused information
  • using echo -n is not portable
  • useless use of cat

Here is what I wrote that is closer to what you should use instead:

i=1
printf %s "Enter pattern $i: "
read -r input
while [[ $input ]]; do
  pattern+=(-e "$input")
  let i++
  printf %s "Enter pattern $i (Enter or Ctrl+D to stop entering patterns): "
  read -r input
done
echo
grep "${pattern[@]}" somefile.txt

EDIT: This does not answer OP's question, this searches for multiple patterns with OR instead of AND...

Here is a working AND solution (it will stop prompting for patterns on the first empty one or after the 4th one):

pattern=
for i in {1..4}; do
  printf %s "Enter pattern $i: "
  read -r input
  [[ $input ]] || break
  pattern="${pattern:+"$pattern && "}/${input//\//\\/}/"
done
echo # skip a line
awk "$pattern" somefile.txt

Here are some links from which you can learn how to program in bash:

Camusensei
  • 1,475
  • 12
  • 20
  • Note you can also use a C-syntax loop and say `for ((i=1; i<=5; i++)); do ...; done`, instead of using `let` (check [How can I add numbers in a bash script](http://stackoverflow.com/a/6348941/1983854) also). +1 for the array trick. Note you can say `input=${input:-""}` for the case when no input is given. – fedorqui Jun 22 '16 at 13:28