esacping single quotes while using egrep in shell script - bash

I need to find some special characters in a given input string .
If the string contains following special characters it should find out.
i am doing egrep to find the characters.
My code is working for every character but not single quotes.
please find my code snippet.
splCharCheck='egrep "&|\"|:|\'" | wc -l'
count=`echo "$Name" | eval $splCharCheck`
Can any one help me how to escape single quotes here?

Don't "escape" the single quote. Check below:
# cat test
'name with quotes'
no quotes
# cat test | egrep "'"
'name with quotes'
# cat test | egrep "\'"
'name with quotes'
no quotes

What are you trying to achieve? This smells like an XY problem.
In bash you can escape text easily using
printf "%q\n" "$Name"
E.g.:
$ Name="Some 'intricate' value"
$ printf "%q\n" "$Name"
Some\ \'intricate\'\ value

You're trying to embed a single-quote inside a double-quoted string which is inside a single-quoted string. The problem is that inside the single-quoted string, the double-quotes aren't treated as anything special, so the single-quote in the middle gets treated as the end of the single-quoted string rather than a part of it. In order to do this, you need to end the single-quoted string ('egrep "&|\"|:|'), escape the lone single-quote some other way (either \' or "'"), then start a new single-quoted string with the rest of what you want ('" | wc -l'). End result:
splCharCheck='egrep "&|\"|:|'\''" | wc -l'
However, I have to agree with #sehe that it looks like you're trying to solve the wrong problem. Why are you putting this command in a variable rather than executing it directly? That's generally a bad idea (and eval just adds more opportunities for things to get weird). And, backing up even further, what are you really trying to do?
p.s. If you must use eval, at least double-quote the string your're eval'ing. Failing to do this can lead to some seriously incomprehensible errors. Finally, I recommend using $( ) instead of backquotes, since it has fewer parsing oddities:
count=$(echo "$Name" | eval "$splCharCheck")

Related

bash: replace single quote with multiple backslashes in variable

I have a variable containing a string with a quote:
echo $variable
It's my variable
to be able to use this variable as a legend for ffmpeg, I need to add 5 backslashes before the quote:
variable="It\\\\\'s my variable"
I'm confused as to what syntax I should use, as the backslashes and quotes have very specific meanings in bash replace commands. I have tried this:
variable=`echo $variable | tr "'" "\\\\\'"`
but it does not produce the correct result
You can just use some single quotes yourself to tell bash not to interpret those slashes:
variable="It"'\\\\\'"'s my variable"
Edit: To convert an existing variable use:
variable=${variable//\'/'\\\\\'\'}
This works fine, is portable and does not have the problems of sed:
echo "$v" |perl -pe "s/'/\x5c\x5c\x5c\x5c\x5c'/g"
PS: \x5c is the ascii code of slash \

shell variable in a grep regex

I'm trying to use a variable in a grep regex. I'll just post an example of the failure and maybe someone can suggest how to make the variable be evaluated while running the grep command. I've tried ${var} as well.
$ string="test this"
$ var="test"
$ echo $string | grep '^$var'
$
Since my regex should match lines which start with "test", it should print the line echoed thru it.
$ echo $string
test this
$
You need to use double quotes. Single quotes prevent the shell variable from being interpolated by the shell. You use single quotes to prevent the shell from doing interpolation which you may have to do if your regular expression used $ as part of the pattern. You can also use a backslash to quote a $ if you're using double quotes.
Also, you may need to put your variable in curly braces ${var} in order to help separate it from the rest of the pattern.
Example:
$ string="test this"
$ var="test"
$ echo $string | grep "^${var}"

Escaping dots in bash variables

I want to escape dots from an IP address in Unix shell scripts (bash or ksh) so that I can match the exact address in a grep command.
echo $ip_addr | sed "s/\./\\\./g"
works (outputs 1\.2\.3\.4), but
ip_addr_escaped=`echo $ip_addr | sed "s/\./\\\./g"`
echo $ip_addr_escaped
Doesn't (outputs 1.2.3.4)
How can I correctly escape the address?
Edit:
It looks like
ip_addr_escaped=`echo $ip_addr | sed "s/\./\\\\\\\./g"`
works, but that's clearly awful!
bash parameter expansion supports pattern substitution, which will look (slightly) cleaner and doesn't require a call to sed:
echo ${ip_addr//./\\.}
Yeah, processing of backslashes is one of the strange quoting-related behaviors of backticks `...`. Rather than fighting with it, it's better to just use $(...), which the same except that its quoting rules are smarter and more intuitive. So:
ip_addr_escaped=$(echo $ip_addr | sed "s/\./\\\./g")
echo $ip_addr_escaped
But if the above is really your exact code — you have a parameter named ip_addr, and you want to replace . with \. — then you can use Bash's built-in ${parameter/pattern/string} notation:
ip_addr_escaped=${ip_addr//./\\.}
Or rather:
grep "${ip_addr//./\\.}" [FILE...]
Replace the double quotes with single quotes.

Search for single quoted grep strings?

I have a string, "$server['fish_stick']" (disregard double quotes)
I don't know how to successfully grep for an exact match for this string. I've tried many ways.
I've tried,
rgrep -i \$'server'\[\''fish'\_'stick'\'\] .
rgrep -i "\$server\[\'fish\_stick\'\]" .
rgrep -i '\$server\[\'fish\_stick\'\]' .
Is it single quotes that are causing my issue?
When I echo the first grep out it shows exactly what I want to search but returns garbage results like anything with $server in it.
Please help and explain, thank you!
The main problem here is that you are not quoting the argument being passed to grep. The only thing that needs to be escaped is \$ (if double quoted) and []. If you want the exact string (not using regex), just use fgrep (grep -F) which does exact string matching:
grep -F "\$server['fish_stick']"
Works on my system:
$ foo="\$server['fish_stick']"
$ echo "$foo" | grep -F "\$server['fish_stick']"
$server['fish_stick']
Using regex:
$ echo "$foo" | grep "\$server\['fish_stick'\]"
$server['fish_stick']
Using regex and handling nested single quotes:
$ echo "$foo" | grep '\$server\['\''fish_stick'\''\]'
$server['fish_stick']
Inside of single quotes, nested single quotes can not be not be escaped. You have to close the quotes, and then reopen it to "escape" the single quotes.
http://mywiki.wooledge.org/Quotes
I don't suppose you're asking how to get that string into a variable without having quoting issues. If you are, here's a way using a here-document:
str=$(cat <<'END'
$foo['bar']
END
)
To address your concern about escaping special characters for grep, you could use sed to put a backslash before any non-alphanumeric character:
grep "$(sed 's/[^[:alnum:]]/\\&/g' <<< "$str")" ...
When used with set -x, the grep command looks like: grep '\$foo\[\'\''bar\'\''\]' ...

How to escape a previously unknown string in regular expression?

I need to egrep a string that isn't known before runtime and that I'll get via shell variable (shell is bash, if that matters). Problem is, that string will contain special characters like braces, spaces, dots, slashes, and so on.
If I know the string I can escape the special characters one at a time, but how can I do that for the whole string?
Running the string through a sed script to prefix each special character with \ could be an idea, I still need to rtfm how such a script should be written. I don't know if there are other, better, options.
I did read re_format(7) but it seems there is no such thing like "take the whole next string as literal"...
EDIT: to avoid false positives, I should also add newline detection to the pattern, eg. egrep '^myunknownstring'
If you need to embed the string into a larger expression, sed is how I would do it.
s_esc="$(echo "$s" | sed 's/[^-A-Za-z0-9_]/\\&/g')" # backslash special characters
inv_ent="$(egrep "^item [0-9]+ desc $s_esc loc .+$" inventory_list)"
Use the -F flag to make the PATTERN a fixed literal string
$ var="(.*+[a-z]){3}"
$ echo 'foo bar (.*+[a-z]){3} baz' | grep -F "$var" -o
(.*+[a-z]){3}
Are you trying to protect the string from being incorrectly interpreted as bash syntax or are you trying to protect parts of the string from being interpreted as regular expression syntax?
For bash protection:
grep supports the -f switch:
-f FILE, --file=FILE
Obtain patterns from FILE, one per line. The empty file contains zero patterns, and therefore matches nothing.
No escaping is necessary inside the file. Just make it a file containing a single line (and thus one pattern) which can be produced from your shell variable if that's what you need to do.
# example trivial regex
var='^r[^{]*$'
pattern=/tmp/pattern.$$
rm -f "$pattern"
echo "$var" > "$pattern"
egrep -f "$pattern" /etc/password
rm -f "$pattern"
Just to illustrate the point.
Try it with -F instead as another poster suggested for regex protection.

Resources