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)
我不知道这里出了什么问题。任何帮助,将不胜感激。
如果 IP 地址始终是该文件的第二个字段,您可以使用awk或cut来提取它。
awk '{print $2}' abd
Run Code Online (Sandbox Code Playgroud)
或者
cut -d' ' -f2 abd
Run Code Online (Sandbox Code Playgroud)
如果您需要遍历 IP 地址,则可以使用通常的for或while循环。例如:
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)
你几乎第一次就做对了。的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每次迭代只需要一个变量。我坚持我的枪在这一点上。
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.1000和abd.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)。