Shell脚本,用于显示文件和目录中每个单词的频率

use*_*000 5 bash shell awk

我在采访中遇到了一个问题

Shell脚本,用于显示文件和目录中每个单词的频率

A
    - A1
        - File1.txt
        - File2.txt
    -A2
        - FileA21.txt
    -A3
        - FileA31.txt
        - FileA32.txt
B
    -B1
        - FileB11.txt
        - FileB12.txt
        - FileB13.txt
    -B2
        -FileB21.txt
Run Code Online (Sandbox Code Playgroud)

我相信通过理解目录A和B是两个单独的目录来理解这个问题,其中A1,A2和A3是A的子目录,B1和B2是B的子目录.所以我这样回答.

Find . ‘\(-name “A” –and –name “B”\)’ –type f –exec cat ‘{}’ \; | awk ‘{c[$1]++} END {for (i in c) print i, c[i]}’
Run Code Online (Sandbox Code Playgroud)

但我仍然得到一个反馈,上面的脚本不够好.给定的脚本有什么问题?

Fil*_*ves 4

主要限制是脚本假设每行只有一个单词。c[$1]++只是增加每行第一个字段的出现次数。

这个问题没有提到任何关于一行中的单词数,所以我认为这不是意图 - 你需要遍历一行中的每个单词。另外,空行怎么办?如果是空行,$1则将是空字符串,因此您的脚本最终将计算“空”单词(它会很高兴地显示为输出的一部分)。

在 awk 中,一行中的字段数存储在内置变量中NF;因此,很容易编写代码来循环遍历单词并增加相应的计数(并且它具有隐式忽略没有单词的行的良好副作用)。

所以,我会做这样的事情:

find . -type f -exec cat '{}' \; | awk '{ for (i = 1; i <= NF; i++) w[$i]++ } END { for (i in w) printf("%-10s %10d\n", i, w[i]) }'
Run Code Online (Sandbox Code Playgroud)

为了简洁起见,我删除了参数 to 中的目录名称约束find(1),并使其更加通用。

这(可能)是您的解决方案的主要问题,但问题(故意)含糊不清,并且还有很多事情需要讨论:

  • 区分大小写吗?该解决方案将Worldworld视为不同的词。这是想要的吗?
  • 标点符号呢?应该你好你好!被视为同一个词吗?那么逗号呢?也就是说,我们需要解析并忽略标点符号吗?
  • 说到这里,像“什么”“什么”之类的事情又如何呢?我们认为它们是不同的词吗?它的对比?英语好难啊!
  • 最重要的是(与上述几点相关),单词的确切定义是什么?我们假设一个单词是一个非空格序列(awk 中的默认值)。这准确吗?
  • 如果输入中没有单词,我们该怎么办?该解决方案不打印任何内容 - 也许我们应该打印一条警告消息?
  • 一行中的字数是固定的吗?还是任意的?(例如,如果每行只有一个单词,那么您的解决方案就足够了)

FWIW,永远记住,你在面试中的成功不是二元是/否。它不像:哎呀,你不能做 X,所以我要拒绝你。或者:哎呀,回答错误,你就出局了。比答案更重要的是实现这一目标的过程,以及您是否意识到 (a) 您所做的假设;(b) 您的解决方案的局限性。上面的问题显示了考虑边缘情况的能力、澄清假设和要求的能力等,这比获得“正确的”脚本更重要(并且可能不存在“正确的脚本”这样的东西)。