Bash - 管道中的变量分配

Bash - 管道中的变量分配

我正在尝试创建一个脚本来监控失败的登录尝试并将这些尝试的 IP 地址作为变量传递。但我遇到了一些麻烦。

我有以下命令,它可以按预期输出 IP 地址。

tail -10 /var/log/authlog | grep '403 Forbidden' | grep -oE '[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}' | sort | uniq | sort

但我正在努力让它们作为变量传递。

tail -10 /var/log/authlog | grep '403 Forbidden' | ip_addr=$(grep -oE '[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}' | sort | uniq | sort) 
echo "The following IPs have failed login '$ip_addr'"

我得到这个作为输出。

The following IPs have failed login ''

任何帮助都将非常感激。

更新:

我仍然无法将输出作为变量传递,所以我决定将其输出到文件中。

tail -10 /var/log/authlog | grep '403 Forbidden' | grep -oE '[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}' | sort | uniq | sort >> iplist.txt

答案1

使用管道中的命令替换进行的变量赋值实际上正在起作用,但是在子 shell 中,而不是在当前正在运行的 shell 中……这就是Bash 中的管道工作原理即,多命令管道中的每个命令(创建管道)都在其自己的子 shell 中执行,这是一个单独的进程) ... 因此,当该部分管道的子 shell 死亡时,所分配的变量也将随之死亡... 请比较以下两种情况:

$ echo "line1 word1 word2" | var="$(grep -o word1)"; echo "${var:-empty}"
empty
$
$ echo "line1 word1 word2" | (var="$(grep -o word1)"; echo "${var:-empty}")
word1

幸运的是,Bash 有一个 shell 选项lastpipe哪个:

如果设置了,并且作业控制未处于活动状态,则 shell 将运行当前 shell 环境中未在后台执行的管道的最后一条命令。

作业控制对于非交互式 Bash shell,即运行可执行脚本文件的那种,默认情况下是停用的./scriptfile...但是,即使在交互式 Bash shell 中,您也可以使用以下命令停用它set +m...请比较以下两种情况:

$ (echo "line1 word1 word2" | var="$(grep -o word1)"; echo "${var:-empty}")
empty
$
$ (shopt -s lastpipe; echo "line1 word1 word2" | var="$(grep -o word1)"; echo "${var:-empty}")
word1

因此,您可以shopt -s lastpipe在管道命令之前将其添加到脚本文件的顶部以启用该行为。

答案2

一旦您通过启用日志记录sudo touch /etc/{w,b}tmp,该sudo lastb命令将显示最新的错误登录列表。

您还可以从fail2ban软件包中学习。fail2ban(1) a set of server and client programs to limit brute force authentication attempts.安装它并阅读文档和脚本。

答案3

更改命令,使变量位于开头而不是中间。例如:

ip_addr=$(tail -10 /var/log/authlog | grep '403 Forbidden' | grep -oE '[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}' | sort | uniq | sort)

相关内容