ここでそんな感じの処理について見かけたので、シェル芸で文章中からの単語の集計(例:「ABCDandABCDorABCDsoABCD」だと、ABCDが4回使われているなど)をシェル芸で一発でできないかなと思ったので、試しにやってみることにした。 まず、文章の中から単語を取得する必要があるのだが、形態素解析だと対象が文章ではなくバラバラな羅列だった場合に使えないので、文章中から1文字づつ範囲をずらして文字を抽出し、それを集計することで使われている文字列を取得することにした。
で、ちょっと長いけど以下のようにすることで、複数回出現した文字列の組み合わせが取得できる。
echo ABCDandABCDorABCDsoABCD|sed 's/ //g'|(A="$(cat)";seq 2 $(wc -c<<<"$A")|xargs -I@ bash -c 'echo "'$A'"|sed -e"p;1s/^.//g;"#{2..@}|(X=$(cat);echo "$X"|grep -Eo .{$(wc -l<<<"$X")})'|sort -u|xargs -I@ bash -c 'echo "'$A'"|grep -o @')|uniq -cd|awk '{print length($2),$0}'|sort -k1nr|awk '
{print $2,$3}'
blacknon@BS-PUB-UBUNTU-01:~$ echo ABCDandABCDorABCDsoABCD|sed 's/ //g'|(A="$(cat)";seq 2 $(wc -c<<<"$A")|xargs -I@ bash -c 'echo "'$A'"|sed -e"p;1s/^.//g;"#{2..@}|(X=$(cat);echo "$X"|grep -Eo .{$(wc -l<<<"$X")})'|sort -u|xargs -I@ bash -c 'echo "'$A'"|grep -o @')|uniq -cd|awk '{print length($2),$0}'|sort -k1nr|awk '{print $2,$3}'
4 ABCD
4 ABC
4 BCD
4 AB
4 BC
4 CD
blacknon@BS-PUB-UBUNTU-01:~$ echo うんことうんこかうんこでうんこ|sed 's/ //g'|(A="$(cat)";seq 2 $(wc -c<<<"$A")|xargs -I@ bash -c 'echo "'$A'"|sed -e"p;1s/^.//g;"#{2..@}|(X=$(cat);echo "$X"|grep -Eo .{$(wc -l<<<"$X")})'|sort -u|xargs -I@ bash -c 'echo "'$A'"|grep -o @')|uniq -cd|awk '{print length($2),$0}'|sort -k1n
r|awk '{print $2,$3}'
4 うんこ
4 うん
4 んこ
で、これでとりあえず動くからいいかと思ってたのだが、@ebanさんがjqコマンドを使ってTwitter上にポストできるくらいに短くされていた。 (jqコマンド、こんなteeみたいな挙動してるのか…)
echo ABCDXXABCD|jq -Rr '. as$i|length as$l|range($l-1)|$i[.:.+range(2;$l-.+1)]'|sort|uniq -cd|awk '$3=length($2)'|sort -nrsk3|awk NF--#シェル芸
— eban (@eban) 2017年9月6日
これを参考に、bashで変数展開を使ってみたところ、もうちょい短く書くことができた。
echo ABCDandABCDorABCDsoABCD|(i=$(cat);l=${#i};seq -f '(i='$i';l='$l';x=%g;eval eval "echo\ \\\${i:$x:{1..$l}}\;")' 0 $l|bash|uniq)|sort|uniq -cd|awk 'length($2)>1{print $0,length($2)}'|sort -k3nr|awk NF--
blacknon@BS-PUB-UBUNTU-01:~$ echo ABCDandABCDorABCDsoABCD|(i=$(cat);l=${#i};seq -f '(i='$i';l='$l';x=%g;eval eval "echo\ \\\${i:$x:{1..$l}}\;")' 0 $l|bash|uniq)|sort|uniq -cd|awk 'length($2)>1{print $0,length($2)}'|sort -k3nr|awk NF--
4 ABCD
4 ABC
4 BCD
4 AB
4 BC
4 CD