Escaping characters for exact grep condition in a Bash script
Solution 1
There are two problems here: as @AFH pointed out, \s
is a Perl shorthand, not part of the standard POSIX syntax. The standard way to represent this is with the character class [[:space:]]
. The second problem is that variable references aren't expanded inside single-quotes; you need to use double-quotes (and escape the $
that's part of the regex).
Also, a few of stylistic recommendations: $( )
is generally preferred over backticks for command substitution (it's easier to read, and doesn't have some weird escaping syntax oddities that backticks have). But in this case, you can skip the command expansion; rather than using wc -l
and comparing to zero to see if there were any matches, just use grep
's exit status as your test (and the -q
option to keep it from printing the match). Also, be sure to double-quote variable references (e.g. in the echo
command).
Here's my recommended rewrite:
if dpkg -l | grep -Eq "(^|[[:space:]])$i(\$|[[:space:]])"; then echo "$i"; fi
EDIT: as igor pointed out in a comment, this won't work with package names that contain regex metacharacters (like g++-5). It's possible to preprocess the package name to escape the metacharacters, but it's rather messy. But there's a simpler way: if you're using bash (and not some other shell), you can use bash's native regex capability to do the matching directly:
if [[ "$(dpkg -l)" =~ (^|[[:space:]])"$i"(\$|[[:space:]]) ]]; then echo "$i"; fi
The reason this works is that the $i
in the middle of the pattern is in double-quotes, which tells bash to match it as a literal string (i.e. ignore any regex metacharacters in it).
Solution 2
Extended Regular Expressions do not support \s
, but Perl REs do, so try using -P
instead of -E
:
dpkg -l | grep -P '(^|\s)rpm($|\s)'
See this reference for more information.
The grep
manual says that -P
is experimental, but it works for me on Ubuntu 16.04.
igor
Updated on September 18, 2022Comments
-
igor over 1 year
I have a basic script for finding specific installed packages in Linux. If not found -> print the package.
I used
grep -w
, but it didn't work properly with the-
character.For example,
dpkg -l | grep -w "rpm"
Will also find
rpm-common
.I found a solution for that using regex. The problem is it doesn't work in a Bash script.
Solution:
dpkg -l | grep -E '(^|\s)string($|\s)'
Condition:
if [ `dpkg -l | grep -E '(^|\s)$i($|\s)' | wc -l` = 0 ]; then echo$i; fi
$i
refers to an array value, likearr[index]=$i
.What escaping characters do I need to use so the condition will work?
-
igor over 6 yearsThis solution doesn't work for packages with special characters. For example
g++-5
org++-4.9
. Any ideas? -
Gordon Davisson over 6 years@igor See edit.