对于目录中具有特定扩展名的文件,我想计算模式后括号中任何变量的所有出现次数。每个文件可能包含多个记录/行上的模式。
到目前为止,我可以处理文件并将结果存储在数组中,但似乎数组会被我处理的每个新文件覆盖。如何保留数组值?
#!/bin/bash
for x in `find . $PROGFILES -name "*.fgl"`
do
awk -f <(cat - <<-'EOF'
/ envget | env-get | \"envget\" | \"env-get\" /
{
gsub( /get-env/, "envget") ;# removes hypens
gsub( /.*envget/, " envget")
gsub( "\\concat" ,"") ;# removes concat
gsub( "\\substring" , "") ;# removes substring
for (i = 1; i<= NF; i++) {
if ( substr( $i, 1, 6) == "envget" ) {
lenofget = 8;
} else {
lenofget = 0;
}
if ( lenofget != 0 ) {
gsub("\\envget" , "",$i) ;#removes envget
gsub ( /\)\.*/, "",$i) ;#removes everything after a closing parenthesis
gsub ( /\47/, "",$i) ;#so used octal instead
gsub ( /\(/, "",$i) ;#removes paraentheses
gsub ( /\"/, "",$i) ;#removes double quotes
gsub ( /\,.*/, "",$i) ;#removes everything after a , This is for any concat syntax
gsub ( /[\/].*/, "",$i) ;#removes everything after a forward slash
narr[$i]++
}
}
}
END {
for (y in narr) {
printf("%s - %d\n",y, narr[y])
}
}
EOF
) $x
done
具有模式的文件中的典型记录/行是:
if envget("SYPSDATA") in {SPACES "."}
set lf-path = "envget"('SYPSCTRL')
if env-get(concat("LOG_PRINTER",service-centre)) != spaces
trconcat(env-get("TMPDIR"),"/ps_xxx_temp.psv")
envget(substring(ws-envprinter1,1,strlen(ws-envprinter1)))
set lf-path = "envget"('SYPSCTRL')
display bitmap concat(envget('BTS')'/images/repedge.gif') @19,44
鉴于有多个文件具有多个模式匹配行,我希望得到这样的输出(其中数字是每个文件中找到的总数)。
BTS - 15
LOG_PRINTER - 7
ws-envprinter1 - 3
SYPSDATA - 120
TMPDIR - 130
SYPSCTRL - 200
答案1
你正在做的
对于“查找”中的 x。 $PROGFILES -名称“*.fgl”` 做 awk(awk_程序)$x 完毕
awk
它为每个文件启动一个新进程。为什么?做就是了
awk(awk_程序)*.fgl "$PROGFILES"/*.fgl
除非您需要搜索子目录。如果您确实需要搜索子目录,则只会稍微复杂一些:
寻找 。 “$PROGFILES”-名称“*.fgl”-exec awk(awk_程序){} +
笔记:
- 您应该始终引用 shell 变量(例如
"$PROGFILES"
和"$x"
),除非您有充分的理由不这样做,并且您确定您知道自己在做什么。 你不需要使用
cat
这样的。您可以将 awk 程序放在引号中:awk ' / envget | env-get | \"envget\" | \"env-get\" / { gsub( /get-env/, "envget") ︙ } ' "$x"
或者你可以将它放入一个文件中并说 .
awk -f (awk_program_file)
- 上述两种方法都不能保证获得总计数,因为命令行的大小有(非常大的)限制。如果您有如此多的文件,其名称的组合长度超过了该限制,
find
将调用多个awk
进程来覆盖所有名称,并且您将返回到获得不完整的计数。处理这个问题的一种方法是收集各个awk
运行的输出并将它们组合起来。
答案2
您的尝试中有几个错误(不是想居高临下,我们都是来学习的!)。
每次调用都是一个不同的进程,具有自己的内存空间,因此一旦处理了文件,下一次调用不保留数组的值awk
是正常的。awk
您需要在每次迭代时输出计数for
,并在最后执行一个额外的步骤来总结所有内容。最简单的方法是将所有这些添加到文件中:
#!/bin/bash
echo "" > "$HOME/tmp_count.txt"
for x in `find . $PROGFILES -name "*.fgl"`
do
awk '
/env-?get/ {
for (i = 1; i<= NF; i++) {
if ($i ~ /env-?get/) {
a = gensub(/.*env-?get\"?\((concat\(|substring\()?(\"|\47)?([a-zA-Z0-9\-_]*)(\"|\47)? *(\)|,)?.*/, "\\3", $i)
arr[a]++
}
}
}
END {
for (y in arr) {
printf("%s %d\n",y, arr[y])
}
}
' "$x" >> "$HOME/tmp_count.txt"
done
awk '{arr[$1] += $2}END{for (key in arr) {printf("%s - %d\n", key, arr[key])}}' < "$HOME/tmp_count.txt"
另外,您的方法似乎并不总是有效,所以我尝试在 a 中使用一个大的正则表达式gensub
,它至少适用于您提供的示例。我不是正则表达式向导,所以它可能会在某些情况下中断。尝试一下,让我知道它是否适合您!