我整理了一个小脚本,该脚本应该在累积唯一字数>的目录中搜索某种类型的文件。 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
,但是在所有文件中对其进行计数?
答案 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" )'