删除列表中的大写/小写dupes

时间:2016-04-23 19:08:26

标签: linux bash macos grep wc

我整理了一个小脚本,该脚本应该在累积唯一字数>的目录中搜索某种类型的文件。 4个字符,但它没有按预期工作。

  1. 无论如何,它都不会消除同一个词。
  2. 我不确定如何计算每个单词的总数。
  3. 最后,这是一种有效的方法(如果它确实有效吗?)。
  4. 脚本:

    #!/bin/bash
    
    file_list=()
    while IFS= read file ; do
        file_list=("${file_list[@]}" "$file")
        tr -sc 'A-Za-z' '\012' < "$file" | sort | uniq -c | egrep "\w{4,}" >> words.txt
    done < <(find . -maxdepth 1 -type f -name "*.c")
    
    # echo "${file_list[@]}"
    
    cat words.txt | sort -u | sort -nr 
    echo "" > words.txt
    

    示例输出:

      38 char
      35 return
      25 static
      18 year
      18 char
      10 COLS
      10 CHAR
    

    如何删除上面示例中的欺骗字char,但是在所有文件中对其进行计数?

3 个答案:

答案 0 :(得分:1)

首先,转换为全小写作为管道中的第一步。

tr A-Z a-z <"$file" | tr -sc a-z '\012' | ...

其次,在整个事物结束时进行排序和计数,而不是在循环内部进行:

...
  tr A-Z a-z <"$file" | tr -sc a-z '\012' 
done < <(find ...) | sort | uniq -c | egrep "\w{4,}" >words.txt

答案 1 :(得分:1)

您只需要:

awk -v RS='\\s' 'length()>3{cnt[tolower($0)]++} END{for (word in cnt) print cnt[word], word}' *.c

以上使用GNU awk进行多字符RS和\s,这是一个简单的调整与其他awks:

awk '{for (i=1;i<=NF;i++) if (length($i)>3) cnt[tolower($i)]++} END{for (word in cnt) print cnt[word], word}' *.c

你问的问题是你当前的方法是否有效 - 不,它的效率非常低,并且比我上面发布的脚本运行速度至少慢一个数量级。阅读why-is-using-a-shell-loop-to-process-text-considered-bad-practice

如果您需要对递归发现的所有文件执行此操作,则可能只需要这些:

awk -v RS='\\s' 'length()>3{cnt[tolower($0)]++} END{for (word in cnt) print cnt[word], word}' $(find -type f -name '*.c' -print)

否则会这样做:

find -type f -name '*.c' -print0 |
xargs -0 cat |
awk -v RS='\\s' 'length()>3{cnt[tolower($0)]++} END{for (word in cnt) print cnt[word], word}'

答案 2 :(得分:0)

以下使用Associative Arrays(Bash 4)将单词存储为键,并将其作为值出现:

declare -A arr
while read -r word; do
    arr[$word]=$(( ${arr[$word]} + 1 ))
done < <(find . -maxdepth 1 -type f -name '*.c' -exec grep -E '\w{4,}' {} \; | tr -s '[:space:]' \\n)

是的,它可以更快地执行,但请注意:如果您将find的{​​{1}}命令终止更改为\;+将还将文件名作为输出的一部分(在我们的例子中是关键)。我们不希望这种行为。因此,如果你有GNU grep - 在grep -h命令终止旁添加find选项。

引自+

man grep

即。 :

  -h, --no-filename
          Suppress the prefixing of file names on output.  This is the default when there is only one file (or only standard input) to search.

为了进行测试,我创建了以下内容:

find . -maxdepth 1 -type f -name '*.c' -exec grep -hE '\w{4,}' {} + | tr -s '[:space:]' \\n

我创建了一个名为 sof 的脚本,其中包含上面的相关代码加上$ cat 1.c 2.c char return char char int char char switch return int CHAR switch COLS year static char CHAR INT int main return case long double 以在执行后验证关联数组内容:

declare -p arr

它看起来不错,所以现在我们可以根据您要求的输出简单地打印它:

$ ./sof
declare -A arr='([return]="3" [static]="1" [switch]="2" [int]="1" [CHAR]="2" [char]="6" [COLS]="1" [double]="1" [main]="1" [case]="1" [long]="1" [year]="1" )'