计算多个文件的每一行上的字符串列表

计算多个文件的每一行上的字符串列表

我有 250 个字符串,我需要计算每个字符串在 400 个文件(最多 20,000 行)的每一行中出现的次数。字符串示例:

journal
moon pig
owls

一个文件的示例:

This text has journal and moon pig
This text has owls and owls

输出示例:

1   0
1   0
0   2

编辑:其中第一列从文件的第一行开始计算字符串,第二列表示文件的第二行。

我有工作代码,但它显然非常慢。我确信 awk 可以加快速度,但我写得还不够好。

for file in folder/*
do
    name=$(basename "$file" .txt)
    linenum=1
    while read line
    do
        while read searches
        do
            ###count every time string appears on line and save
            count=$(echo $line | grep -oi "$searches" | wc -l)
            echo $count >> out/${name}_${linenum}.txt
        done < strings.txt
        linenum=$((linenum+1))
    done < $file
done

编辑:我像这样粘贴了 400 次,其中 x 是原始文件中的行数。

paste out/file1_{1..x}.txt > out/file1_all.txt

有谁知道如何加快速度?

答案1

如果

$ cat strings
journal
moon pig
owls

$ cat file
I like to journal about owls and moon pigs.
owls are birds. moon pigs are not.
owls owls owls

然后,你可以像这样使用 GNU awk

gawk '
    NR == FNR { string[++n] = $0; next}
    {
        for (i=1; i<=n; i++)
            # gsub() return the number of replacements.
            # it is a convenient way to count instances of fixed strings.
            count[i][FNR] = gsub(string[i], string[i])
        if (FNR > max)
            max = FNR
    }
    END {
        for (i=1; i<=n; i++) {
            for (j=1; j<=max; j++)
                printf "%s\t", 0 + count[i][j]
            print ""
        }
    }
' strings file

输出

1   0   0
1   1   0
1   1   3

我根本没有解释过那个 awk 程序。看看你是否能弄清楚,并提出你的任何问题。

答案2

获取每行计数数组并立即处理每行的核心算法是:

gawk ' NR == FNR { string[++n] = $0; next}
       { for (i=1; i<=n; i++) 
             printf("%s\t", gsub(string[i],""))
         print ""
       }
     ' strings file

这是基于 gsub 来给出执行的替换的计数。

这将生成以下输出:

1   1   0   
0   0   2

这只是您所要求的转置矩阵。在 awk 中转置列和行有点复杂。并且还可以处理多个文件。我们可以使用空行作为文件更改的指示符来连接(管道)两个脚本。处理同一个文件两次:

awk '
    NR == FNR { string[++n] = $0; next}
    FNR==1 && p == 1 { print "" }
    { for (i=1; i<=n; i++) printf("%s\t", gsub(string[i],""))
      print ""
      p = 1
    }
    END    { print "" }
' strings.txt    infile.txt    infile.txt |
awk '!/^$/{ 
       for(i=1;i<=NF;i++) f[NR-r][i]=$i ;
       if (maxf<NF) maxf = NF ;
       if (maxr<(NR-r)) maxr = NR-r ;
     } 
     /^$/{
         for(      i=1 ; i<=maxf ; i++ )
         {
             for(  j=1 ; j<=maxr ; j++ )
                 printf("%s\t",f[j][i])
             print ( "loop", maxf, maxr, r )
         }
     r=NR
     print ( "" )
     maxf=0
     maxr=0
     delete f
     }'

这给出了所问的答案:

1   0
1   0
0   2

1   0
1   0
0   2

相关内容