I'm trying to find IPs from whitelist IP list for nginx configuration.
/tmp/iplist
:
11.2.3.4
22.2.3.4
/tmp/whitelist
:
"1.2.3.4"
"11.2.3.4"
"1.2.3.44"
"11.2.3.44"
And when I run grep like grep '"11.2.3.4"' /tmp/whitelist
, I can get a right answer like "11.2.3.4"
.
However, within a bash script, I could not get any answers.
Here are some patterns that I tried:
/tmp/findIPs.sh
:
#!/bin/bash
for ip in $(cat /tmp/iplist)
do
grep '"$ip"' /tmp/whitelist
grep '\"$ip\"' /tmp/whitelist
grep '\\\"$ip\\\"' /tmp/whitelist
x="\"$ip\""
fgrep '$x' /tmp/whitelist
grep '$x' /tmp/whitelist
y="$ip"
fgrep '$y' /tmp/whitelist
grep '$y' /tmp/whitelist
And, this is a result, which is blank.
> bash /tmp/findIPs.sh
>
What is the point that I missing?
The simplest adaptation of the code you're using is:
for ip in $(cat /tmp/iplist)
do
grep "$ip" /tmp/whitelist
done
Once you've got the value in the variable, its double quotes aren't damaged by further double-quoted variable expansion. If the /tmp/iplist
file doesn't contain the double quotes but they're critical, then you can use:
grep "\"$ip\"" /tmp/whitelist
or you could use this:
grep \""$ip"\" /tmp/whitelist
(and there are two asymmetric permutations available too). It's a good idea to make sure you do know why that works. There are some ways to use single quotes if you want to, but the "$ip"
part must be outside of the single quotes.
All your examples start the pattern argument to grep
with a single quote. Single quotes suppress all expansions until the next single quote. So, for example, grep '"$ip"' /tmp/whitelist
is looking for 5 characters — "
, $
, i
, p
, "
— in the file. In none them is the variable ip
ever expanded.
There will be problems if any IP address ever gets a space in it. Be cautious about using for ip in $(cat /tmp/iplist)
. Very often you'd do better with:
while read -r ip
do
grep "$ip" /tmp/whitelist
done < /tmp/iplist
Another way to do this is with grep -F
or fgrep
:
grep -F -f /tmp/iplist /tmp/whitelist
This doesn't insist on double quotes around the IP addresses, but makes a single pass over the /tmp/whitelist
file (and a single pass over the /tmp/iplist
file too), which is about as efficient as it gets. This will produce lines in a slightly different order from before, which probably won't matter, but you should be aware of it.
If you must have the double quotes (to avoid selecting 11.2.3.44
when searching for 11.2.3.4
, then:
grep -F -f <(sed 's/^/"/; s/$/"/' /tmp/iplist) /tmp/whitelist
This uses process substitution to pass an edited version of the /tmp/iplist
file to the grep
command. If you don't have process substitution in your shell, you can probably use:
sed 's/^/"/; s/$/"/' /tmp/iplist | grep -F -f - /tmp/whitelist
which makes grep
read the list of patterns to match from standard input instead of a named file. If perchance -f -
doesn't work (e.g. because you're working on a Mac using macOS, or probably a BSD machine), then -f /dev/stdin
probably will, or -f /dev/fd/0
.
You could also generate the /tmp/iplist
file with the double quotes in place. You could generate the /tmp/whitelist
file without the double quotes and then use grep -x
to specify an exact match.
In case you haven't already gathered, there are quite a lot of different ways to do this.