端末から、ファイル内の単語の文字を数える簡単な方法はありますか?


8

ファイルに1億行あります。

各行には1つの列しかありません。

例えば

aaaaa
bb
cc
ddddddd
ee

文字数を記載したい

このような

2 character words - 3
5 character words - 1
7 character words - 1

ターミナルでこれを行う簡単な方法はありますか?


回答:


20
$ awk '{ print length }' file | sort -n | uniq -c | awk '{ printf("%d character words: %d\n", $2, $1) }'
2 character words: 3
5 character words: 1
7 character words: 1

最初のawkフィルターは、というファイルの各行の長さを出力するだけですfile。このファイルには1行に1ワードが含まれていると想定しています。

sort -n(の出力からソート行awk昇順に数値)とuniq -c(各行が連続発生回数をカウント)を与えられたデータのためのものから次の出力を作成します。

   3 2
   1 5
   1 7

次に、これは、awk各行を「X文字のY文字を持つ行」と解釈する2番目のスクリプトによって解析され、必要な出力が生成されます。


代替の解決策は、それをすべて行いawk、長さの数を配列に保持することです。効率、読みやすさ、理解しやすさ(したがって保守性)の間のトレードオフであり、どのソリューションが「最適」か。

代替ソリューション:

$ awk '{ len[length]++ } END { for (i in len) printf("%d character words: %d\n", i, len[i]) }' file
2 character words: 3
5 character words: 1
7 character words: 1

awkでソートする必要はありません(デフォルトでは、数値でインデックス付けされた配列がソートされます)(高速)。
Isaac

@矢印私は知っています。Sundeepが数秒で私をそれに打ち負かしたので、私はその解決策をコメントでコメントアウトしています。最後の段落でもこれについて触れています。
クサラナンダ

コメントは、ソリューションのユーザーにとって役立つはずです(回答(またはSundeepの回答)には含まれていません:-)…)。それ以外の場合:回答に同じ効果のコメントを含めてください。私は喜んで私のコメントを削除します。:-)
アイザック

10

すべてでそれを行う別の方法awkだけでは

$ awk '{words[length()]++} END{for(k in words)print k " character words - " words[k]}' ip.txt 
2 character words - 3
5 character words - 1
7 character words - 1
  • words[length()]++ 入力行の長さをキーとして使用してカウントを保存する
  • END{for(k in words)print k " character words - " words[k]} すべての行が処理された後、配列の内容を目的の形式で出力します


パフォーマンスの比較、選択された数値は2つの実行のうち最良

$ wc words.txt
 71813  71813 655873 words.txt
$ perl -0777 -ne 'print $_ x 1000' words.txt > long_file.txt
$ du -h --apparent-size long_file.txt
626M    long_file.txt

$ time awk '{words[length()]++} END{for(k in words)print k " character words - " words[k]}' long_file.txt > t1

real    0m20.632s
user    0m20.464s
sys     0m0.108s

$ time perl -lne '$h{length($_)}++ }{ for $n (sort keys %h) {print "$n character words - $h{$n}"}' long_file.txt > t2

real    0m19.749s
user    0m19.640s
sys     0m0.108s

$ time awk '{ print length }' long_file.txt | sort -n | uniq -c | awk '{ printf("%d character words - %d\n", $2, $1) }' > t3

real    1m23.294s
user    1m24.952s
sys     0m1.980s

$ diff -s <(sort t1) <(sort t2)
Files /dev/fd/63 and /dev/fd/62 are identical
$ diff -s <(sort t1) <(sort t3)
Files /dev/fd/63 and /dev/fd/62 are identical

ファイルにASCII文字のみが含まれる場合、

$ time LC_ALL=C awk '{words[length()]++} END{for(k in words)print k " character words - " words[k]}' long_file.txt > t1

real    0m15.651s
user    0m15.496s
sys     0m0.120s

時間perlがあまり変わらなかった理由がわからない。おそらくエンコードを他の方法で設定する必要がある


私はちょうど私の独自のソリューションにそれを追加しました。私はあなたのものを見たときにそれを削除しました。:-)
クサラナンダ

ええ、私はあなたの編集を
見直す

数値でインデックス付けされた配列をソートする必要はありません。それは常に増加するインデックスで注文されます。(まあ、少なくともawkでは:
Isaac

lengthなしで()完全に罰金ここ作品なので、中括弧を追加するために冗長かもしれません。ただし、GNU awkを使用しています。
Sergiy Kolodyazhnyy 2017年

2
うん@SergiyKolodyazhnyy、GNU awkのマニュアルは言うIn older versions of awk, the length() function could be called without any parentheses. Doing so is considered poor practice, although the 2008 POSIX standard explicitly allows it, to support historical practice. For programs to be maximally portable, always supply the parentheses
Sundeep

5

以下はperl同等のものです(with -optional-sort):

$ perl -lne '
    $h{length($_)}++ }{ for $n (sort keys %h) {print "$n character words - $h{$n}"}
' file
2 character words - 3
5 character words - 1
7 character words - 1

キーインデックスが数値の場合:キー配列はPerlでソートする必要がありますか?
アイザック

1
@Arrow:この回答はハッシュ(つまり、文字列キーを持つ連想配列)を使用しており、それらには未定義のキー順序があるため、はい。実際、キーは数値ではなく文字列としてソートされるため、答えは少しバグがあります。{$a<=>$b}後に追加するsortと、修正されます。あるいは、数値キーを持つ通常の配列を使用して、値がゼロまたは未定義のキーをスキップすることもできます。
Ilmari Karonen

@IlmariKaronenよろしくお願いします。中括弧はどのような違いがありますか?
Isaac

ハッシュの代わりに配列を使用する方が効率的です。OPは数百万行を必要とするため、印刷中にゼロをチェックしてスキップすることによるオーバーヘッドは、安価なインデックス付けによって簡単に補われます。
Peter Cordes

5

代替1つの使用してのGNU AWKの呼び出し、printf関数を

$ awk 'BEGIN { PROCINFO["sorted_in"] = "@ind_str_asc"}
       {c[length($0)]++}
       END{
           for(i in c){printf("%s character words - %s\n",i,c[i])}
          }' infile
2 character words - 3
5 character words - 1
7 character words - 1

コアアルゴリズムは、配列内の文字数を収集するだけです。最後の部分は、printfでフォーマットされた収集されたカウントを出力します。

awkへの高速でシンプルな1回の呼び出し。

正確には、配列を維持するためにさらに多くのメモリが使用されます。
しかし、ソートは呼び出されず(数値配列のインデックスは、PROCINFOで常に上向きにソートされるようにトラバースされるように設定されています)、複数ではなく1つの外部プログラムのみawkです。


1
for in少なくともいくつかの値またはいくつかのawk実装では、数値配列インデックスを数値順に与える場合がありますが、これは必須ではなく、伝統的ではなく、普遍的ではありません。2、3、または4のような小さなセットでよく発生します。(gawkでPROCINFOまたはWHINY_USERSを使用せずに)アクセスできるすべてのawkで10または20を試してください。
dave_thompson_085

ご入力いただきありがとうございます。これを使用する:私はそれが今ソートされていると思います。:-)
アイザック

1
@ind_str_asc文字列として並べ替えます。これは、数値がすべて1桁の場合にのみ適切です(例のように)。@ind_num_asc(任意の)値が10以上の場合に使用します。また、以前ほど問題ではなくなっていますが、この機能はgawk 4.0以降のみです。
dave_thompson_085 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.