如何计算某个短语在文件中出现的次数并整齐地格式化它?

如何计算某个短语在文件中出现的次数并整齐地格式化它?

我有一个日志文件,我试图从中提取数据。它的格式如下,并列出某些模块何时签入和签出:

19:50:26 (license_manager) OUT: "certain_module" [email protected]
19:50:28 (license_manager) IN: "rarely_used_module" [email protected]
19:50:28 (license_manager) IN: "certain_module" [email protected]
19:50:28 (license_manager) IN: "different_module" [email protected]
19:50:38 (license_manager) OUT: "certain_module" [email protected]
19:50:38 (license_manager) OUT: "different_module" [email protected]

到目前为止我有以下内容。我特别感兴趣的是“rarely_used_module”何时被检查以及由谁检查:

cd /path/to/script && cat logfile.txt | grep -c "rarely_used_module" 

但这只是给了我计数,除此之外什么也没有。我想让它变得更加复杂有两个原因:了解有关 shell 脚本的更多信息并在该脚本中实现更多的 bash 概念,其次,我希望它能够告诉我许可证的签出时间以及哪个用户查看了它。

绝对理想的情况是计算该许可证被签出的次数并将其格式化为某种表格以供参考。这可能吗?

更新#1

所需的输出,如下所示。我将在下面提出一个理论示例,其中很少使用的模块已被 2 个唯一用户检出 4 次,两次单独检出:

Number of license checkouts for rarely_used_module: 4 
User : [email protected] (2)
User : [email protected] (2)

本质上,我想要该模块被签出的总次数,并且我想要签出该许可证的用户的姓名。我知道我可以抓住“rarely_used_module”的 OUT: 行,但我不知道如何处理它。

答案1

对于您更新的问题:

awk '
/"rarely_used_module"/ && /OUT:/ { nc[$NF]++ ; c++ }
END {
    printf "Number of license checkouts for rarely_used_module: %d\n", c
    for (i in nc) printf "User: %s (%d)\n", i, nc[i]
}
' logfile.txt

创建此输出:

Number of license checkouts for rarely_used_module: 4
User: [email protected] (2)
User: [email protected] (2)



我将原始答案保留在下面,以展示如何扩展代码,以防您增加需求。

以下是如何使用以下方法完成此类任务的示例awk

awk '
BEGIN { SUBSEP = ", " ; OFS = ": " }
{ m[$(NF-1)]++ }
{ n[$(NF-1)] = n[$(NF-1)] " " $NF }
{ nc[$(NF-1),$NF]++ }
END {
    print "\n=== count modules:"
    for (i in m) print i, m[i]
    print "\n=== collect names using modules:"
    for (i in n) print i, n[i]
    print "\n=== count names using modules:"
    for (i in nc) print i, nc[i]
}
' logfile.txt

解释:

  • { m[$(NF-1)]++ }- 增加输入数据中倒数第二个字段(模块)的计数器
  • { n[$(NF-1)] = n[$(NF-1)] " " $NF }- 连接每个键(模块)的最后一个字段(名称)
  • { nc[$(NF-1),$NF]++ }- 增加(名称,模块)键元组的计数器

使用您的示例数据,它将产生以下输出:

=== count modules:
"rarely_used_module": 1
"different_module": 2
"certain_module": 3

=== collect names using modules:
"rarely_used_module":  [email protected]
"different_module":  [email protected] [email protected]
"certain_module":  [email protected] [email protected] [email protected]

=== count names using modules:
"different_module", [email protected]: 1
"different_module", [email protected]: 1
"certain_module", [email protected]: 2
"rarely_used_module", [email protected]: 1
"certain_module", [email protected]: 1

答案2

当我需要比更改或匹配每一行更复杂的东西时,我使用Python,因为它是通用语言。它可能比awk(顺便说一句,有一个pawkPython awk)更详细,但它也为您提供了记录良好且易于扩展的代码。

以下是适合您任务的 Python 2 脚本:

from collections import defaultdict

FILE = 'module.txt'

# Global table of usages is 
# dict [ module_name ] -> dict [ user_name ] -> count
usage = defaultdict(lambda : defaultdict(int))

# Read, parse data and add usage count where needed
with open(FILE) as f:
    for line in f:
        # Split using spaces and pick last 2 fields, 
        # strip unncessary characters
        fields = line.split()     
        user = fields[-1].rstrip()
        module_name = fields[-2].strip('"')

        usage[module_name][user] += 1

# Now print pretty results
for module_name, module_usage in usage.items():
    print '====> ', module_name
    for user, count in module_usage.items():
        print '\t', user, count

它将打印您的样本的以下数据:

====>  different_module                                                                                                                                                        
        [email protected] 1
        [email protected] 1
====>  rarely_used_module
        [email protected] 1
====>  certain_module
        [email protected] 2
        [email protected] 1

相关内容