여러 파일의 각 줄에 있는 문자열 목록 계산

여러 파일의 각 줄에 있는 문자열 목록 계산

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

관련 정보