我创建了带有“AND”条件的简单 bash 脚本,但不起作用:
#!/bin/bash
cat log3.txt | \
while read -r LINE
do
if [[ $LINE =~ Host ]] && [[ $LINE =~ denied ]] ; then echo $LINE;
fi
done
这是 log3.txt 的内容
Host: abcd.com
Access denied
如果使用 OR 条件,它运行良好,但我想使用 AND 条件,因此如果日志同时包含字符串“Host”和“Access Denied”,我将得到输出。
答案1
在循环的任何一次迭代中while
,该值$LINE
不能同时存在Host
和 denied
。考虑到文件中的数据,这是不可能的。这就是为什么你没有得到输出。
如果您想查看文件中与这两个单词匹配的所有行Host
或者 denied
,grep
改为使用:
grep -wF -e 'Host' -e 'Access denied' <log3.txt
这里使用的选项将确保我们进行字符串比较而不是正则表达式匹配 ( -F
),并且我们匹配完整的单词而不是子字符串 ( -w
)。给出两个查询字符串-e
,我们将得到包含以下内容的任何行任何这些。
如果您想进行稍微更高级的查询,仅显示包含两个单词(如果它们都出现在文件中)的行,那么您可以使用程序来完成awk
:
awk '/Host/ { hostline=$0 } /Access denied/ { deniedline=$0 }
END { if ((hostline != "") && (deniedline != ""))
print hostline; print deniedline; }' <log3.txt
在这里,如果我们找到与 string 匹配的行Host
,我们将保存它,对于 string 也是如此Access denied
。最后,如果两个字符串都包含任何内容,我们将打印它们。
在或多或少等效的 shell 代码中:
#!/bin/sh
while IFS= read -r line; do
case $line in
*Host*)
hostline=$line ;;
*"Access denied"*)
deniedline=$line ;;
esac
done <log3.txt
if [ -n "$hostline" ] && [ -n "$deniedline" ]; then
printf '%s\n%s\n' "$hostline" "$deniedline"
fi
这里我用一条case ... esac
语句对读取到的数据进行匹配。使用的模式是文件名通配模式,而不是正则表达式。
有关的:
答案2
如果您确定要处理的文件很小(如您的示例),您可以一次性读取整个文件并测试:
file=$(<log3.txt)
[[ $file =~ Host ]] && [[ $file =~ denied ]] && echo "$file"
对于较大的文件,并假设Host
您denied
可以使用更快的(对于外部文件)sed:
<log3.txt sed -n '/^Host/!d;p;:1;n;/\<denied\>/{p;q};b1'
了解此解决方案将严格打印以 和 开头的第一Host
行下列的(不在同一行)第一的包含denied
单词的行。
如果您需要提取一些对Host
- denied
,将 更改q
为 a b
,这将重新开始循环:
<log3.txt sed -n '/^Host/!d;p;:1;n;/\<denied\>/{p;b};b1'
awk 的类似解决方案将打印Host
一行之前的最后一行denied
(成对):
awk ' p==1 && /\<denied\>/ {d=$0;p=0}
/^Host*/ {h=$0;p=1}
{ if(p==0&&h!=""&&d!="") {print h,RS,d;p=2} }
' <log3.txt
shell 中的逻辑相同(除了它会匹配denied
行上的任何位置(而不是单词)):
#!/bin/sh
p=0
while IFS= read -r line; do
if [ "$p" = 1 ]; then
case $line in
*denied*) deniedline=$line; p=0 ;;
esac
fi
case $line in
Host*) hostline=$line; p=1 ;;
esac
if [ "$p" = 0 ] && [ "$hostline" ] && [ "$deniedline" ]; then
printf '%s\n%s\n' "$hostline" "$deniedline"
p=2
fi
done <log3.txt
答案3
请参阅@Kusalananda 答案,了解为什么您的解决方案不起作用。
我的解决方案使用grep -z
:
grep -zEo -e 'Host: (\w|\.)+\s+Access denied\s' log.txt
慢动作:
-E
:使用扩展正则表达式-o
:仅打印匹配项-z
: 用作\0
行分隔符。由于没有,搜索是在整个文件上完成的,其中\n
只是一个普通字符。- e'Host: (\w|\.)+\s+Access denied\s'
: 寻找:- ”
Host:
“ - 字母、数字或点的序列
- 太空级角色(将是
\n
) - ”
Access denied
“ - 一个太空级角色(将是
\n
)。这个需要在输出上换行
- ”
运行于:
Host: denied1.com
Access denied
Host: ok.com
Access OK
Host: random.com
Host: denied2.com
Access denied
More stuff
产量:
Host: denied1.com
Access denied
Host: denied2.com
Access denied