たいちょーの雑記

ぼくが3日に一度くらい雑記をかくところ

第65回シェル芸勉強会に参加しました

参加しました。今回は自宅からリモート参戦でした。

新生シェル芸Botがめちゃいい感じでしたね。整備ありがとうございます!!

この参加記では時間中の自分の解答と、解きなおしのPowerShell解をしたりしなかったりします。

Q1

以下のようなinputファイルがあります

a bb ccc dddd
eeee fff gg
h ii

このファイルから次のような出力を得るという問題

a bb
a ccc
a dddd
eeee fff
eeee gg
h ii

ヤバそうな気がしますねえ。

cat Sh*/vol.65/input | stairl | awk 'NF!=1{print $1,$NF}'

stairlはegzactのコマンドです。

github.com

stairlを使うと以下のようになります

$ cat Sh*/vol.65/input | stairl
a
a bb
a bb ccc
a bb ccc dddd
eeee
eeee fff
eeee fff gg
h
h ii

目的の出力得るためには、1列以上ある行について、各行の先頭と最後を選択すればよさそうです。なのであとはawkでエイヤという感じにしました。

ところで、問題の制約としてtarrなどのツールやawkforを使わずにというのがあったのでそれにも挑戦してみます。

$ sel 1 2 1::2 1::3 -f ./Sh*/vol.65/input | \
  juz 3 sed 's/ /\n/2' | \
  awk 'NF!=1&&$1!=$2'

sel[n]:[m]:[k]を使うと[n]から[m]まで[k]個ごとに出力するクエリです。なので1::2は1列目から2列ごとに出力するものです。この場合は以下のような出力になります

a bb a ccc a dddd
eeee fff eeee gg eeee
h ii h h

後は2個ずつ改行して必要なデータだけ取り出して終わりです。sedは何回か繰り返す必要があるのですが、これにはjuzを使いました。便利です。

PowerShell解は↑で疲れたのでスキップです

Q2

input内容を以下のように加工する問題

a dddd bb dddd ccc dddd
eeee gg fff gg
h ii

最後の列を毎列ごとに差し込むって感じですね。Q1で出た解答を参考にした感じです。解説は配信をご覧ください。

cat Sh*/vol.65/input | \
  awk 'gsub(FS, FS$(NF)FS)' | \
  sel :-2

こっちはPowerShell解を書きます

$ cat She*/*.65/input |
  %{ $x=($_ -split ' ');  $_ -replace ' ',(" " + $x[-1] + " ") } |
  sel -- :-2
a dddd bb dddd ccc dddd
eeee gg fff gg
h ii

手法自体は同じです。書き方が違うというだけですね。awkに慣れてると、ForEach-Objectでは毎回splitしないといけないことがめんどくさく感じちゃいますね。なんかいい方法あったりするんでしょうか。

Q3

eeeeeeファイルの内容をランレングス圧縮する問題です。

cat Sh*/vol.65/eeeeee | grep -oP '(.)\1*' | awk '$0=$1NF' FS= ORS=

grepで文字ごとに行に分割します。あとはawkで数えつつ連結するって感じです。awkの部分はTLを見てて賢いな~と思ったのを参考にしています。

ところでjuliaにはランレングスするrle()という関数があるようです。これでやってみます

cat ./Sh*/vol.65/e* | \
  sel -d '' 0 | \
  julia -E 'using StatsBase;rle(split(readline()))' | \
  sel -d'[' 2: | \
  tr '\]\)' \\n | \
  tr -d ,\" | \
  rs -T  | \
  tr -d \ \\n

出力の整形を結構頑張る必要がありますが、ロジックを自前実装する必要がないのがいいですね。

Q4

symbolsファイルは以下のような内容です

a->
c-)
g~>
>-z->
)-d-)
>~y~>
)-e
>-f
>~i~>
>~j

これを矢印の種類でまとめてくださいという問題。時間内に解けなかったので解説を参考にした解答を張っておきます。

cat Sh*/vol.65/sy* | \
  sed -r 's/^([a-z])(.)(.)/\3\2\1\2\3/;s/../& /' | \
  awk '{a[$1]=a[$1]$0}END{for(x in a) print a[x]}' | \
  sel -D '' 2:

PowerShell解は以下です

$ cat She*/*.65/sy* | 
  %{ @{k=$_ -replace '^[a-z](.)(.)','$2$1' -replace '^(..).+','$1';v=$_} } | 
  group -Property k | 
  %{ ($_.Group|%{$_.v}) -join '' }
c-))-d-))-e
a->>-z->>-f
g~>>~y~>>~i~>>~j

左側の矢印をキーにGroup Byすればいいってことに気づいたので、PowerShellGroup-Objectでやってみました。便利だ便利。こんな感じでGroup Byしてくれるコマンド、欲しくなりますね。

Q5

wordsファイルは以下のような内容です

ang ker
ora ch
pea eat
spea nge
rep le

1列目、2列目を組み替えて、意味のある単語にしてくださいという問題

$ join -j9 Sh*/vol.65/words{,} | awk '$0=$1$NF' | grep -x -f- /usr/share/dict/words

join -j9awkですべての組み合わせを列挙し、/usr/share/dict/wordsに存在する単語を選ぶという感じです。

PowerShellはどうすればいいんだ…?

Q6

echo 焼肉定食からはじめて総画数を計算するという問題。すごいぜ。

$ wget https://raw.githubusercontent.com/cjkvi/cjkvi-tables/master/joyo2010.txt
$ echo 焼肉定食 | grep -o . | grep -f- ./joyo2010.txt | sel -a -- -3 | jq -s add

画数とかがまとまってるデータをwgetしてきて、漢字をgrepで検索。あとは該当のカラムを選んで足すという感じです。

PowerShell解は以下の通りです。

$ echo 焼肉定食 | 
  %{ $_ -split '' } | 
  ?{ $_ } | 
  %{ ((sls $_ .\joyo2010.txt) -split '\s')[2] } | 
  measure -Sum | 
  %{$_.Sum}

echo 焼肉定食で始めることを意識してこんな感じに仕上げてみました。大体のことは組み込みでできますね。

Q7

kimファイルの内容から総画数が素数な行を取り出す問題。

$ cat Sh*/vol.65/kim | \
  while read N; do
    echo $N $(echo $N | grep -o . | grep -f- ./joyo2010.txt| sel -a -- -3 | jq -s add|factor);
  done | \
  awk 'NF==3{print $1}'

Q6の解答を拡張しただけですね。

LT

今回はLTさせていただきました!
内容としては呪符式高速詠唱シェル芸の続きです。読み取りに使うOCRを複数個にすることで誤認識を減らそうというアイデアを実装したものになります。
最後のライブコーディングでも正しく読み取れたので良かったです!
聞いてくださった方ありがとうございました!

おわり

最近はjuliaegzactといった便利なツールを学んだことで、複雑なことを短いコマンドでできるようになりました。それもいいんですが、コマンドを組み合わせることと情報を足して処理しやすくすることも大切だなと感じる問題が多かったです。どっちもできるようになりたいですね。

今回も準備・運営ありがとうございました!

| ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|
|        終        |
|    制作・著作    |
|   ̄ ̄ ̄ ̄ ̄ ̄ ̄  |
|    xztaityozx    |
|_________|
  ∧∧   ||         
  ( ゚д゚)||           
  /    づΦ