从文本中提取 IP 地址并将其存储在变量中

Swa*_*are 6 grep shell-script text-processing regular-expression

我有一个名为 abd 的文本文件,如下所示。

48878 128.206.6.136
34782 128.206.6.137
12817 23.234.22.106
Run Code Online (Sandbox Code Playgroud)

我只想从文本中提取 IP 地址并将其存储在变量中并用于其他目的。

我试过这个。

for line in `cat abd`
do

ip=`grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' $line`

echo $ip

done
Run Code Online (Sandbox Code Playgroud)

我收到如下错误

grep: 34782: No such file or directory

grep: 128.206.6.137: No such file or directory

grep: 12817: No such file or directory

grep: 23.234.22.106: No such file or directory
Run Code Online (Sandbox Code Playgroud)

我不知道这里出了什么问题。任何帮助,将不胜感激。

cas*_*cas 9

如果 IP 地址始终是该文件的第二个字段,您可以使用awkcut来提取它。

awk '{print $2}' abd
Run Code Online (Sandbox Code Playgroud)

或者

cut -d' ' -f2 abd
Run Code Online (Sandbox Code Playgroud)

如果您需要遍历 IP 地址,则可以使用通常的forwhile循环。例如:

for ip in $(cut -d' ' -f2 abd) ; do ... ; done
Run Code Online (Sandbox Code Playgroud)

或者

awk '{print $2}' abd | while read ip ; do ... ; done
Run Code Online (Sandbox Code Playgroud)

或者您可以将所有 IP 地址读入一个数组:

$ IPAddresses=($(awk '{print $2}' abd))
$ echo "${IPAddresses[@]}"
128.206.6.136 128.206.6.137 23.234.22.106
Run Code Online (Sandbox Code Playgroud)


rub*_*ils 8

你几乎第一次就做对了。的awk回答是你的具体情况不错,但你收到一个错误的原因是因为你试图使用grep,就好像它在寻找一个文件,而不是一个变量。

另外,在使用正则表达式时,我总是使用grep -E只是为了安全。我还听说反引号已被弃用,应替换为$().

使用grep支持herestrings 的外壳上的变量的正确方法是对其中 3 个使用输入重定向:<,因此您的grep命令($ip变量)实际上应如下所示:

ip="$(grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' <<< "$line")"
Run Code Online (Sandbox Code Playgroud)

如果它是您正在搜索的文件,我总是使用while循环,因为它可以保证逐行进行,而for如果有任何奇怪的间距,循环通常会被丢弃。您还实现了一个无用的使用,cat它也可以被输入重定向替换。尝试这个:

while read line; do
  ip="$(grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' <<< "$line")"
  echo "$ip"
done < "abd"
Run Code Online (Sandbox Code Playgroud)

另外,我不知道grep您使用的是什么操作系统或版本,但是我过去使用此命令时,通常不需要在花括号之前使用的转义字符。它可能来自使用grep -E或因为我在引号中使用它并且没有反引号 - 我不知道。您可以尝试使用或不使用它,看看会发生什么。

无论您使用for循环还是while循环,这取决于在您的特定情况下哪个适合您,以及执行时间是否最重要。在我看来,OP 似乎并没有尝试为每个 IP 地址分配单独的变量,但他想为该行内的每个 IP 地址分配一个变量,以便他可以在循环本身中使用它——其中如果他$ip每次迭代只需要一个变量。我坚持我的枪在这一点上。


Rob*_*rtL 7

grep搜索模式的文件或标准输入。您不能在grep命令行上传递要匹配的数据字符串。尝试这个:

grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' abd
Run Code Online (Sandbox Code Playgroud)

如果您需要获取变量中的每个 IP 地址:

grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' abd |
while read IP
do
    echo "$IP"
done
Run Code Online (Sandbox Code Playgroud)

已接受答案的比较性能测试

答案建议grep在输入文件的每一行上执行单独的调用。让我们看看如何处理 1000 到 5000 行的文件。这些文件abd.1000abd.5000被简单地复制在问题最初的例子文件中创建。原始代码仅更改为将文件名作为命令行参数 ( ${1:?}) 而不是硬编码的“abd”。

$ wc -l abd.1000 abd.5000
  1000 abd.1000
  5000 abd.5000
  6000 total
Run Code Online (Sandbox Code Playgroud)

在 1000 行文件上测试此答案中的示例代码:

$ cat ip-example.sh
#!/bin/sh
grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' "${1:?}" |
while read IP
do
    echo "$IP"
done

$ time sh ip-example.sh abd.1000 > /dev/null

real    0m0.021s
user    0m0.007s
sys     0m0.017s
$
Run Code Online (Sandbox Code Playgroud)

上面显示这个答案中的示例在不到 1/4 秒的时间内处理了一个 1000 行的文件。现在让我们看看已接受答案中的示例如何执行:

$ cat accepted.sh
#!/bin/bash
while read line; do
  ip="$(grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' <<< "$line")"
  echo "$ip"
done < "${1:?}"

$ time bash accepted.sh abd.1000 > /dev/null

real    0m3.565s
user    0m0.739s
sys     0m2.936s
$
Run Code Online (Sandbox Code Playgroud)

嗯。已接受答案中的示例在 3 1/2 秒内执行,比此答案示例中的 1/40 秒169 倍

让我们加大赌注并用 5000 行进行测试:

$ time sh ip-example.sh abd.5000 > /dev/null

real    0m0.052s
user    0m0.051s
sys     0m0.029s
Run Code Online (Sandbox Code Playgroud)

处理5 倍多的数据所需的时间大约是原来的两倍

$ time bash accepted.sh abd.5000 > /dev/null

real    0m17.561s
user    0m3.817s
sys     0m14.333s
Run Code Online (Sandbox Code Playgroud)

已接受答案中的示例代码处理 5 倍于处理 1000 行数据所需的时间几乎是其5 倍

结论

已接受答案中的示例处理 5000 行文件所需的时间ip-example.sh此答案中的代码长 337 倍(此页面上的其他答案应与 类似ip-example.h)。