在日志文件中找到模式后提取 IP 地址
Extract IP address after pattern is found in log file
我需要在 bash 脚本中使用 ipset
命令提取并阻止日志文件中的某个 IP 地址(仅限 IPv4)。日志文件结构如下所示:
[Line 1] random text
[Line 2] random text
...
[Line 26] random text
Aug 31 13:40:14 [logs ] con_accept: [759] connection from 127.0.0.1:56860 is successfull on 0.0.0.0:25000
[Line 28] random text
...
[Line 38] random text
Aug 31 13:40:57 [logs ] _authrequest: [759] random text client connected and the sky is blue today more random text
[Line 40] random text
- 忘记添加每行
[Line 1] ... [Line X
以时间戳 Aug 31 13:40:14 [logs ] con_accept: [759] connection from 127.0.0.1:56860 is successful on 0.0.0.0:25000
开头
- 需要提取和阻止的IP地址将显示在匹配模式的行之前的最后15行内。在这种情况下,可以在
Line 27
. 找到
- 脚本首先搜索
sky is blue
字符串
- 找到字符串后,它会在匹配的字符串行之前打印最后一个
15 lines
并提取匹配 [759]
的 IP 地址,即 clientID
- 为避免误报和错误块,
[ID]
必须匹配,在本例中 [759]
匹配 Line 39 and Line 27
。 clientID
不是预定义的数字,因此它会发生变化。只能是数字。
- IPv4 地址
127.0.0.1
将被提取,然后使用 ipset add blacklist $IP
阻止
到目前为止,我是 grep
或 awk
用法。找到模式后检查最后 15 行很容易,但是,我正在尝试进行额外检查并在 string is found
和 clientID
匹配后提取正确的 IP 地址。
awk 'c-->0;[=11=]~s{if(b)for(c=b+1;c>1;c--)print r[(NR-c+1)%b];print;c=a}b{r[NR%b]=[=11=]}' b=15 s="sky is blue" logfile
grep -B 15 'sky is blue' logfile
当您使用 awk 时,您永远不需要额外的 grep(或 sed)。
如果您的系统上有 tac
那么:
$ cat tst.sh
#!/usr/bin/env bash
ip=$(
tac "${@:--}" |
awk -v b=15 -v s='sky is blue' '
[=10=] ~ s {
endNr = NR + b
id =
}
( == "con_accept:") && ( == id) {
sub(/:.*/,"",)
ip =
}
NR == endNr { exit }
END {
if ( ip == "" ) {
exit 1
}
else {
print ip
}
}
'
) &&
echo ipset add blacklist "$ip"
$ ./tst.sh file
ipset add blacklist 127.0.0.1
否则使用 GNU awk 处理数组数组的效率较低:
$ cat tst.sh
#!/usr/bin/env bash
ip=$(
awk -v b=15 -v s='sky is blue' '
{ id = }
== "con_accept:" {
sub(/:.*/,"",)
ips[NR][id] =
}
[=12=] ~ s {
for (n=NR-1; n>(NR-b); n--) {
if ( (n in ips) && (id in ips[n]) ) {
ip = ips[n][id]
exit
}
}
}
END {
if ( ip == "" ) {
exit 1
}
else {
print ip
}
}
' "${@:--}"
) &&
echo ipset add blacklist "$ip"
$ ./tst.sh file
ipset add blacklist 127.0.0.1
当您完成测试并对结果感到满意时,请删除 echo
。
以上假定您问题中每行开头的 [Line N]
字符串实际上并不存在。如果是,则可以轻松调整为每个字段编号使用添加 2。
简单的第一关:
grep -nB 15 'sky is blue' logfile | sort -nr
grep -n
将在每一行前面加上文件中的行号(格式:<line_number>:<contents_of_line>
)。
sort -rn
将使用数字排序以相反的顺序对行进行排序。
从这里您可以将这些行传递给 bash/while
循环或 awk
脚本,请记住几个(潜在的)问题:
- 找不到'sky is blue'怎么办?
- 如果 'sky is blue' 有多个匹配项怎么办?处理第一个、最后一个或所有实例?
- 如果给定的 clientID 有多个匹配行但 IP 地址不同怎么办?处理第一个、最后一个或所有 IP 地址?
- 是否所有感兴趣的行都具有与示例数据中显示的完全相同的格式,还是可能需要编码的格式不同?
'当然,所有这些都可以通过单个 awk
脚本(例如,Ed Morton 的回答)以多种不同的方式编码...
我需要在 bash 脚本中使用 ipset
命令提取并阻止日志文件中的某个 IP 地址(仅限 IPv4)。日志文件结构如下所示:
[Line 1] random text
[Line 2] random text
...
[Line 26] random text
Aug 31 13:40:14 [logs ] con_accept: [759] connection from 127.0.0.1:56860 is successfull on 0.0.0.0:25000
[Line 28] random text
...
[Line 38] random text
Aug 31 13:40:57 [logs ] _authrequest: [759] random text client connected and the sky is blue today more random text
[Line 40] random text
- 忘记添加每行
[Line 1] ... [Line X
以时间戳Aug 31 13:40:14 [logs ] con_accept: [759] connection from 127.0.0.1:56860 is successful on 0.0.0.0:25000
开头
- 需要提取和阻止的IP地址将显示在匹配模式的行之前的最后15行内。在这种情况下,可以在
Line 27
. 找到
- 脚本首先搜索
sky is blue
字符串 - 找到字符串后,它会在匹配的字符串行之前打印最后一个
15 lines
并提取匹配[759]
的 IP 地址,即clientID
- 为避免误报和错误块,
[ID]
必须匹配,在本例中[759]
匹配Line 39 and Line 27
。clientID
不是预定义的数字,因此它会发生变化。只能是数字。 - IPv4 地址
127.0.0.1
将被提取,然后使用ipset add blacklist $IP
阻止
到目前为止,我是 grep
或 awk
用法。找到模式后检查最后 15 行很容易,但是,我正在尝试进行额外检查并在 string is found
和 clientID
匹配后提取正确的 IP 地址。
awk 'c-->0;[=11=]~s{if(b)for(c=b+1;c>1;c--)print r[(NR-c+1)%b];print;c=a}b{r[NR%b]=[=11=]}' b=15 s="sky is blue" logfile
grep -B 15 'sky is blue' logfile
当您使用 awk 时,您永远不需要额外的 grep(或 sed)。
如果您的系统上有 tac
那么:
$ cat tst.sh
#!/usr/bin/env bash
ip=$(
tac "${@:--}" |
awk -v b=15 -v s='sky is blue' '
[=10=] ~ s {
endNr = NR + b
id =
}
( == "con_accept:") && ( == id) {
sub(/:.*/,"",)
ip =
}
NR == endNr { exit }
END {
if ( ip == "" ) {
exit 1
}
else {
print ip
}
}
'
) &&
echo ipset add blacklist "$ip"
$ ./tst.sh file
ipset add blacklist 127.0.0.1
否则使用 GNU awk 处理数组数组的效率较低:
$ cat tst.sh
#!/usr/bin/env bash
ip=$(
awk -v b=15 -v s='sky is blue' '
{ id = }
== "con_accept:" {
sub(/:.*/,"",)
ips[NR][id] =
}
[=12=] ~ s {
for (n=NR-1; n>(NR-b); n--) {
if ( (n in ips) && (id in ips[n]) ) {
ip = ips[n][id]
exit
}
}
}
END {
if ( ip == "" ) {
exit 1
}
else {
print ip
}
}
' "${@:--}"
) &&
echo ipset add blacklist "$ip"
$ ./tst.sh file
ipset add blacklist 127.0.0.1
当您完成测试并对结果感到满意时,请删除 echo
。
以上假定您问题中每行开头的 [Line N]
字符串实际上并不存在。如果是,则可以轻松调整为每个字段编号使用添加 2。
简单的第一关:
grep -nB 15 'sky is blue' logfile | sort -nr
grep -n
将在每一行前面加上文件中的行号(格式:<line_number>:<contents_of_line>
)。
sort -rn
将使用数字排序以相反的顺序对行进行排序。
从这里您可以将这些行传递给 bash/while
循环或 awk
脚本,请记住几个(潜在的)问题:
- 找不到'sky is blue'怎么办?
- 如果 'sky is blue' 有多个匹配项怎么办?处理第一个、最后一个或所有实例?
- 如果给定的 clientID 有多个匹配行但 IP 地址不同怎么办?处理第一个、最后一个或所有 IP 地址?
- 是否所有感兴趣的行都具有与示例数据中显示的完全相同的格式,还是可能需要编码的格式不同?
'当然,所有这些都可以通过单个 awk
脚本(例如,Ed Morton 的回答)以多种不同的方式编码...