bash 脚本中带双引号的 grep
grep with double quotation in bash script
我正在尝试从 nginx 配置的白名单 IP 列表中查找 IP。
/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"
当我 运行 像 grep '"11.2.3.4"' /tmp/whitelist
这样的 grep 时,我可以得到像 "11.2.3.4"
这样的正确答案。
然而,在 bash 脚本中,我无法得到任何答案。
以下是我尝试过的一些模式:
/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
而且,这是一个空白的结果。
> bash /tmp/findIPs.sh
>
我漏掉了什么?
您使用的代码的最简单改编是:
for ip in $(cat /tmp/iplist)
do
grep "$ip" /tmp/whitelist
done
一旦您获得变量中的值,它的双引号就不会被进一步的双引号变量扩展损坏。如果 /tmp/iplist
文件不包含双引号但它们很重要,那么您可以使用:
grep "\"$ip\"" /tmp/whitelist
或者你可以使用这个:
grep \""$ip"\" /tmp/whitelist
(还有两个不对称排列可用)。确保您确实知道它为什么有效是个好主意。如果需要,有一些方法可以使用单引号,但是 "$ip"
部分必须在单引号之外。
您的所有示例都以单引号开始 grep
的模式参数。单引号抑制所有扩展,直到下一个单引号。因此,例如,grep '"$ip"' /tmp/whitelist
正在文件中查找 5 个字符 — "
、$
、i
、p
、"
。在 none 中,它们是不断扩展的变量 ip
。
如果任何 IP 地址中包含 space,就会出现问题。谨慎使用 for ip in $(cat /tmp/iplist)
。通常你会做得更好:
while read -r ip
do
grep "$ip" /tmp/whitelist
done < /tmp/iplist
另一种方法是使用 grep -F
或 fgrep
:
grep -F -f /tmp/iplist /tmp/whitelist
这并不坚持在 IP 地址周围使用双引号,而是对 /tmp/whitelist
文件进行一次传递(并且对 /tmp/iplist
文件也进行一次传递),这大约是尽可能高效。这将以与之前略有不同的顺序生成行,这可能无关紧要,但您应该注意这一点。
如果必须要双引号(为了避免搜索11.2.3.4
时选择11.2.3.44
,那么:
grep -F -f <(sed 's/^/"/; s/$/"/' /tmp/iplist) /tmp/whitelist
这使用 process substitution 将 /tmp/iplist
文件的编辑版本传递给 grep
命令。如果您的 shell 中没有进程替换,您可以使用:
sed 's/^/"/; s/$/"/' /tmp/iplist | grep -F -f - /tmp/whitelist
这使得 grep
从标准输入而不是命名文件中读取要匹配的模式列表。如果碰巧 -f -
不起作用(例如,因为您正在使用 macOS 或可能是 BSD 机器在 Mac 上工作),那么 -f /dev/stdin
可能会,或者 -f /dev/fd/0
.
您还可以生成带有双引号的 /tmp/iplist
文件。您可以生成不带双引号的 /tmp/whitelist
文件,然后使用 grep -x
指定完全匹配。
如果你还没有收集到,有很多不同的方法可以做到这一点。
我正在尝试从 nginx 配置的白名单 IP 列表中查找 IP。
/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"
当我 运行 像 grep '"11.2.3.4"' /tmp/whitelist
这样的 grep 时,我可以得到像 "11.2.3.4"
这样的正确答案。
然而,在 bash 脚本中,我无法得到任何答案。
以下是我尝试过的一些模式:
/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
而且,这是一个空白的结果。
> bash /tmp/findIPs.sh
>
我漏掉了什么?
您使用的代码的最简单改编是:
for ip in $(cat /tmp/iplist)
do
grep "$ip" /tmp/whitelist
done
一旦您获得变量中的值,它的双引号就不会被进一步的双引号变量扩展损坏。如果 /tmp/iplist
文件不包含双引号但它们很重要,那么您可以使用:
grep "\"$ip\"" /tmp/whitelist
或者你可以使用这个:
grep \""$ip"\" /tmp/whitelist
(还有两个不对称排列可用)。确保您确实知道它为什么有效是个好主意。如果需要,有一些方法可以使用单引号,但是 "$ip"
部分必须在单引号之外。
您的所有示例都以单引号开始 grep
的模式参数。单引号抑制所有扩展,直到下一个单引号。因此,例如,grep '"$ip"' /tmp/whitelist
正在文件中查找 5 个字符 — "
、$
、i
、p
、"
。在 none 中,它们是不断扩展的变量 ip
。
如果任何 IP 地址中包含 space,就会出现问题。谨慎使用 for ip in $(cat /tmp/iplist)
。通常你会做得更好:
while read -r ip
do
grep "$ip" /tmp/whitelist
done < /tmp/iplist
另一种方法是使用 grep -F
或 fgrep
:
grep -F -f /tmp/iplist /tmp/whitelist
这并不坚持在 IP 地址周围使用双引号,而是对 /tmp/whitelist
文件进行一次传递(并且对 /tmp/iplist
文件也进行一次传递),这大约是尽可能高效。这将以与之前略有不同的顺序生成行,这可能无关紧要,但您应该注意这一点。
如果必须要双引号(为了避免搜索11.2.3.4
时选择11.2.3.44
,那么:
grep -F -f <(sed 's/^/"/; s/$/"/' /tmp/iplist) /tmp/whitelist
这使用 process substitution 将 /tmp/iplist
文件的编辑版本传递给 grep
命令。如果您的 shell 中没有进程替换,您可以使用:
sed 's/^/"/; s/$/"/' /tmp/iplist | grep -F -f - /tmp/whitelist
这使得 grep
从标准输入而不是命名文件中读取要匹配的模式列表。如果碰巧 -f -
不起作用(例如,因为您正在使用 macOS 或可能是 BSD 机器在 Mac 上工作),那么 -f /dev/stdin
可能会,或者 -f /dev/fd/0
.
您还可以生成带有双引号的 /tmp/iplist
文件。您可以生成不带双引号的 /tmp/whitelist
文件,然后使用 grep -x
指定完全匹配。
如果你还没有收集到,有很多不同的方法可以做到这一点。