使用awk匹配日志文件中的一列并打印整行 [英] using awk to match a column in log file and print the entire line

查看:517
本文介绍了使用awk匹配日志文件中的一列并打印整行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个脚本来分析日志文件, 我想让用户选择输入模式,然后在特定列(第五行)中打印与该模式匹配的任何行 终端上的以下作品

awk ' $5=="acpid:" {print$0}' *filename*

好的,所以上面我试图匹配"acpid:"这很好,但是在脚本中我希望能够允许多个条目并搜索所有条目,问题是我弄乱了脚本中的变量是我所拥有的:

echo "enter any services you want details on, seperated by spaces"
read -a details
for i in ${details[@]}    
do 
        echo $i
        awk '$5 == "${i}" {print $0}' ${FILE}
done

再次,如果我直接输入匹配的表达式而不是它起作用的变量,那么我想我的问题是任何提示都很棒

更新

所以即时通讯使用@ghoti建议的第二个选项(如下所示),因为它与我的日志文件匹配得更好 但是我没有很多条目的运气.香港专业教育学院添加了两行来说明结果,即得到的结果是echo $ i和echo"finish loop",它们应该告诉我该循环当前在什么输入上,而我正在离开该循环

    'read -a details
    re=""

    for i in "${details[@]}"; do
    re="$re${re:+|}$i"

     echo $i
     echo"finish loop"
    done

    awk -v re="$re" '$5 ~ re' "$FILE" `

当我分别输入"acpid"或"init"的输入时,会匹配一个完美的结果,但是当输入是"acpid init"时,则输出为

acpid初始化
完成循环

我从中看到的是,读取将两个单词作为一个条目,然后awk正在搜索但不匹配它们(这是预期的).因此,为什么不将输入视为两个单独的条目,我曾认为-a选项与read一起指定将由空格分隔的单词放置在数组的单独元素中.也许我没有正确声明数组?

更新更新

好,取消上述更新,就像我傻瓜一样,我忘记了ID将IFS更改为\ n之前的脚本,并将其更改为宾果游戏!

再次感谢@ghoti的帮助!

解决方案

您可以通过几种方法完成自己想做的事情.

一个选择可能是对每个单词进行一个for循环,然后对awk进行不同的调用,并顺序显示结果.例如,如果您在$details变量中输入foo bar,则可能会得到一个foo匹配项列表,然后是一个bar匹配项列表:

read -a details
for i in "${details[@]}"; do
  awk -v s="$i" '$5 == s' "$FILE"
done

这里的想法是我们使用awk的-v选项将每个单词放入脚本中,而不是在引用的脚本中扩展变量.您应该阅读 bash如何处理不同种类的报价. (有关该主题的一些Stackoverflow问题,请此处

结果将包含$FILE中所有有趣的行,并按它们出现在$FILE中的顺序排列,而不是按您提供的单词进行排序.

请注意,这是一个非常基本的搜索,没有单词边界,因此,如果搜索"foo bar babar",可能会得到不需要的结果.不过,您可以自己使用正则表达式. :)

这能回答您的问题吗?

I'm trying to write a script which will analyse a log file, i want to give the user the option to enter a pattern and then print any line which matches this pattern in a specific column (the fifth one) the following works from the terminal

awk ' $5=="acpid:" {print$0}' *filename*

ok so above im trying to match "acpid:" this works fine but in the script i want to be able to allow multiple entries and search for them all, the problem is i'm messing up the variable in the script this is what i have:

echo "enter any services you want details on, seperated by spaces"
read -a details
for i in ${details[@]}    
do 
        echo $i
        awk '$5 == "${i}" {print $0}' ${FILE}
done

again if i directly put in a matching expression instead of the variable it works so i guess my problem is here any tips would be great

UPDATE

So im using the second option suggested(shown below) by @ghoti as it matches my log file slightly better however im not having any luck with multiple entries. ive added two lines to illustratre the results im getting these are echo $i and echo "finish loop" as placed they should tell me what input the loop is currently on and that im leaving the loop

    'read -a details
    re=""

    for i in "${details[@]}"; do
    re="$re${re:+|}$i"

     echo $i
     echo"finish loop"
    done

    awk -v re="$re" '$5 ~ re' "$FILE" `

When i give read an input of either "acpid" or "init" seperately a perfect result is matched, however when the input is "acpid init" the following is the output

acpid init
finish loop

What im seeing from this is that the read is taking the both words as one entry and then the awk is searching but not matching them (as would be expected). so why is the input not being taken as two separate entries i had thought the -a option with read specified that words separated by a space would be placed into separate elements of the array. perhaps i have not declared the array correctly?

Update update

ok cancel the above update like i fool i'd forgotten that id chaged IFS to \n earlier in the script changed it back and bingo !!!

Many thanks again to @ghoti for his help!!

解决方案

There are a few ways that you could do what you want.

One option might be to run through a for loop for each word, then apply a different call to awk, and show the results sequentially. For example, if you entered foo bar into the $details variable, you might get a list of foo matches, followed by a list of bar matches:

read -a details
for i in "${details[@]}"; do
  awk -v s="$i" '$5 == s' "$FILE"
done

The idea here is that we use awk's -v option to get each word into the script, rather than expanding the variable inside the quoted script. You should read about how bash deals with different kinds of quotes. (There are also a few Stackoverflow questions on the topic, here and here and elsewhere.)

Another option might be to construct a regular expression that searches for all the words you're interested in, all at once. This has the benefit of using a single run of awk to search through $FILE:

read -a details
re=""
for i in "${details[@]}"; do
  re="$re${re:+|}$i"
done
awk -v re="$re" '$5 ~ re' "$FILE"

The result will contain all the interesting lines from $FILE in the order in which they appear in $FILE, rather than ordered by the words you provided.

Note that this is a fairly rudimentary search, without word boundaries, so if you search for "foo bar babar", you may get results you don't want. You can play with the regex yourself, though. :)

Does that answer your question?

这篇关于使用awk匹配日志文件中的一列并打印整行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆