views:

164

answers:

3

I have a user input that would be used in a search string that may contain a metacharacter

For e.g. C# or C++

my grep command in a function was:

grep -E "$1|$2" test.txt

under direct replacement:

grep -E "C\+\+|testWord" test.txt
grep -E "C\#|testWord" test.txt

the first caught the lines fine but not the second. Strangely, # was completely ignored. Without direct replacement, both catch anything with c followed by testWord instead of c++ and c# respectively

I've tried handling it using sed

$temp = `echo $1 | sed 's/[\#\!\&\;\`\"\'\|\*\?\~\<\>\^\(\)\[\]\{\}\$\+\\]/\\&/g'`

but it doesn't work right. Or is there any other way to handle user input with metacharacters?

Thanks in advance

A: 

This works for me:

$ testfun1(){ echo "foo $1" | grep "$1"; }
$ testfun1 C#
foo C#
$ testfun2(){ read a; echo "bar $a" | grep "$a"; }
$ testfun2
C#
bar C#

Edit:

You might try this form without -E:

$ testfun3(){ grep "$1\|$2" test.txt; }
$ testfun3 C++ awk
something about C++
blah awk blah
$ testfun3 C# sed
blah sed blah
the text containing C#
$ testfun3 C# C++
something about C++
the text containing C#
Dennis Williamson
It does work but not with two variables.I realised my grep statement was wrong. It's corrected now but still is unable to handle strings with metacharacters :(
eruina
A: 

if you are passing the input as arguments to the script

#!/bin/bash

input1="$1"
input2="$2"
while read -r line
do
    case "$line" in
        *$input1*|*$input2* ) echo "found: $line";;
    esac
done  <"BooksDB.txt

"

output

$ cat file
this is  a line
this line has C++ and C#
this line has only C++ and that's it
this line has only C# and that's it
this is end line Caa

$ ./shell.sh C++ C#
found: this line has C++ and C#
found: this line has only C++ and that's it
found: this line has only C# and that's it

if you are getting input from read

read -p "Enter input1:" input1
read -p "Enter input2:" input2
while read -r line
do
    case "$line" in
        *$input1|*$input2* ) echo "found: $line";;
    esac
done <"BooksDB.txt"
ghostdog74
I've tried with two variables with the following code: fileContents = cat BookDB.txt; case "*$1*$2*" in *fileContents* ) echo "found!";; esaccouldn't find anything at allI was passing theh input as arguments to the scriptSorry I don't know how to format code in the comments. It looks pretty messy.. >.<
eruina
see new edit. no need for cat. just do a while read loop using the shell.
ghostdog74
A: 

Just quote all the grep metacharacters in $1 and $2 before adding them to your grep expression.

Something like this:

quoted1=`echo "$1" | sed -e 's/\([]\.?^${}+*[]\)/\\\\\1/g'`
quoted2=`echo "$2" | sed -e 's/\([]\.?^${}+*[]\)/\\\\\1/g'`
grep -E "$quoted1\|$quoted2" test.txt

ought to work. Adjust the metachar list to suit. Handling | is a little tricky because backslashing makes it special, but since we're already backslashing backslashes I think it's safe.

garyo
i noticed two [] in the enclosed \( and \), what is the purpose of adding the second one? and in the replacement string, i only understood the purpose of 3 \, 2 to make the first back slash that would be appended in front, the last one to represent \1. what would the last two be for?
eruina