たいちょーの雑記

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

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

参加しました

今回もリモート開催でした。

配信のURLはこちらです。

明日はちょっと時間とれなさそうなので、今回は開催当日の投稿です。というわけで時間中に解答できたものだけ記述します。PowerShell解はありません。

Q1

「おらおら」とか「へいへい」みたいな (..)\1にマッチしそうな文字列がちょうど2個含まれる行を行番号とともに出力する問題。おらおら!

$ cat Sh*/*54/oraora.txt | nl | while read R L; do [[ $(grep -oPe "(..)\1" <<< $L | sort | uniq -c | awk '$0=$1' | jq -s add ) == 2 ]] && echo $R $L ; done

nlでとりあえず行番号を付与し、while readの力業です。ここではRに行番号、Lに対象の文字列が入るので、条件にあう文字列かどうかを評価してechoするかどうかを決めています。なんか解答みてたらつよい正規表現が出てきてすごいなと思いました(こなみ)

Q2

偶数行にが書かれているファイルkouun.txtで、矢印の向いている奇数行を出力する問題。どういうことかというと

うんこ
↑

これはが「うんこ」を指しているので「うんこ」を出力する

これは
↑
シェル芸
↓
勉強会

これだと「シェル芸」は指されてないので出力しないといった具合。やってみます

$ cat Sh*/*54/kouun.txt | pee "grep -B1 ↑" "grep -A1 ↓" | grep -vPe "↑|↓|--" | sort -u

grepABはマッチした行のN行前後を出力するオプション。ならそのひとつ前。ならそのひとつ後を取り出すようにします。これを同時にやりたいので今回はmoreutilsのpeeを使いました。ただ、これだと順番は無視されちゃいますね

Q3

human.txtにある絵文字を解析して、男性を表す(MAN|BOY)な絵文字の数、女性を表す(GIRL|WOMAN)な絵文字の数をそれぞれ数え上げる問題。

$ cat She*/*54/human.txt | uni i | sort | uniq -c | awk '$10~/^(BOY|MAN)$/{a+=$1}$10~/^(GIRL|WOMAN)$/{b+=$1}END{print "男:"a, "女:"b}'

家族の絵文字は男性や男の子、女性、女の子といった絵文字をZWJで連結することで表現されます。なのでuninameのような文字のユニコード情報を返すコマンドを使えばあとは集計するだけですね。ここではuni

https://github.com/arp242/uni

Q4

yoko.txtのうちあ行の文字の個数、か行の文字の個数、さ行の文字の個数・・・・わ行の文字の個数をそれぞれ集計する問題。

$ cat She*/*54/yoko.txt | grep -o . | uconv -x latin | sed -E 's/^.$/a&/;s/^(.).+/\1/;y/aksctnhmyrw/あかさたたなはまやらわ/' | sort | uniq -c | sort -r

uconv -x latinを使うことでローマ字読みに変換できます。あとは子音をあかさたなはまやらわに置換してやれば sort | uniq -c | sortで集計ができますね。

Q5

小問1

Figure1Figure2_032321.fastaというファイルから、一番長い同じ文字が連続する文字列とそれが含まれる行の行番号を出力する問題。

$ grep -nEo -e{A,G,T,C}+ ./Figure1Figure2_032321.fasta | awk -F: '{print $0, length($2)}' | sort -nrk2 | head -n1
106:CCCCCC 6

小問2

同ファイルの改行を無視したときの場合を出力する問題。こっちは無理だった。

Q6

jugem.txtを以下のような形に変形して下さいという問題

寿水行ころパイーリンポ
限の末とやポポグンポコ
無魚雲むぶイののダのナ
寿水来住らパシンイーの
限利末にこポュガグピ長
無砂風ろうイーンーコ久
五海来こじパリリリポ命
劫れ末とのじンーンンの
のき食るぶうガュダポ長
すりう寝らこンシイの助

縦書きっぽいけど、蛇腹のようになっています。これは…teipの出番っぽいですね。

$ cat She*/*54/jugem.txt | grep -oPe .{10} | teip -l 2,4,6,8,10 -- rev | sed 's/./& /g' | rs -T | tr -d ' '
寿水行ころパイーリンポ
限の末とやポポグンポコ
無魚雲むぶイののダのナ
寿水来住らパシンイーの
限利末にこポュガグピ長
無砂風ろうイーンーコ久
五海来こじパリリリポ命
劫れ末とのじンーンンの
のき食るぶうガュダポ長
すりう寝らこンシイの助

teipで偶数行だけrev、あとは転置するだけですね。

Q7

nejineji.txtは以下のようなファイルです

寿限無寿限無五劫のすりきれ
            海
じのぶらこうじパイポパ 砂
う         イ 利
こ グーリンダイグ ポ 水
ら の     ー パ 魚
ぶ ン コピー リ イ の
や ガ ポ   ン ポ 水
ろ ン ンポのイダ の 行
こ リ       シ 末
と ーュシンガンリーュ 雲
む           来
住にろことる寝う食末来風末

これを一行に直してくださいという問題。ヤダ!!!!!!!!!!!!!!!!!

$ A="$(cat Sh*/*54/nejineji.txt|sed 's/./& /g')";while [[ "$A" != "" ]]; do echo $A|head -n1;A="$(echo $A|tail -n+2|rs -T|tac)";done | sed -zEe 's/ | |\n//g'

問題のnejineji.txtをよく観察してみると文字がぐるぐる巻きになっていることがわかりますね。というわけで1行目を取り出して回転、1行目を取り出して回転、を繰り返せばよさそうです。とりあえず試してみましょう

一行目の取り出しは以下でいいでしょう

$ head -n1 ./nejineji.txt
寿限無寿限無五劫のすりきれ

そして2行目以降を転置させてみます。各文字を要素としたいのでsedで空白区切りに変えておきます。

$ tail -n+2 ./nejineji.txt | sed 's/./& /g' | rs -T 
   じ  う  こ  ら  ぶ  や  ろ  こ  と  む  住
   の                             に
   ぶ     グ  の  ン  ガ  ン  リ  ー     ろ
   ら     ー                 ュ     こ
   こ     リ     コ  ポ  ン     シ     と
   う     ン     ピ     ポ     ン     る
   じ     ダ     ー     の     ガ     寝
   パ     イ           イ     ン     う
   イ     グ  ー  リ  ン  ダ     リ     食
   ポ                       ー     末
   パ  イ  ポ  パ  イ  ポ  の  シ  ュ     来
                                 風
海  砂  利  水  魚  の  水  行  末  雲  来  末

rs -Tで転置をすると次に取り出したい行が最後尾に来ることがわかります。これをtacコマンドを使って上下を反転すれば…

$ tail -n+2 ./nejineji.txt | sed 's/./& /g' | rs -T | tac
海  砂  利  水  魚  の  水  行  末  雲  来  末
                                 風
   パ  イ  ポ  パ  イ  ポ  の  シ  ュ     来
   ポ                       ー     末
   イ     グ  ー  リ  ン  ダ     リ     食
   パ     イ           イ     ン     う
   じ     ダ     ー     の     ガ     寝
   う     ン     ピ     ポ     ン     る
   こ     リ     コ  ポ  ン     シ     と
   ら     ー                 ュ     こ
   ぶ     グ  の  ン  ガ  ン  リ  ー     ろ
   の                             に
   じ  う  こ  ら  ぶ  や  ろ  こ  と  む  住

こうなります。ここで気付いてほしいのは、これが最初の状態から90度回転させた状態になっていることです。ということは、これを繰り返せば最終的には1行になりそうですね。

ではこれを繰り返すような処理を書いていきます。ここでは読みやすいように改行した状態で示します

$ A="$(cat nejineji.txt|sed 's/./& /g')";
$ while [[ "$A" != "" ]]; do 
  echo $A | head -n1
  A="$(echo $A|tail -n+2|rs -T|tac)"
done
寿 限 無 寿 限 無 五 劫 の す り き れ
海  砂  利  水  魚  の  水  行  末  雲  来  末
風  来  末  食  う  寝  る  と  こ  ろ  に  住
む  と  こ  ろ  や  ぶ  ら  こ  う  じ   
                               
                            
                            
                        の
ぶ  ら  こ  う  じ  パ  イ  ポ  パ
イ  ポ  パ  イ  ポ  の  シ  ュ
ー  リ  ン  ガ  ン  シ  ュ  ー
リ  ン  ガ  ン  の  グ   
                   
                
                
            ー
リ  ン  ダ  イ  グ
ー  リ  ン  ダ
イ  の  ポ  ン
ポ  コ   
       
    
    
ピ
ー

おお~。いいですね。あとは余計な改行や空白を削除しましょう。

$ A="$(sed 's/./& /g' nejineji.txt)"; while [[ "$A" != "" ]]; do head -n1 <<< $A; A="$(tail -n+2 <<< $A|rs -T|tac)"; done | sed -zEe 's/ | |\n//g'
寿限無寿限無五劫のすりきれ海砂利水魚の水行末雲来末風来末食う寝るところに住むところやぶらこうじのぶらこうじパイポパイポパイポのシューリンガンシューリンガンのグーリンダイグーリンダイのポンポコピー

できました。とんでもない問題でした。

再帰を使って書いてみたのが以下です。やっていること自体は同じです。気が向いたら読んでみてください。

$ a(){ A="$(cat)"; [[ "$A" == "" ]] && return; head -n1 <<< $A; tail -n+2 <<< $A | rs -T | tac | a }; sed 's/./& /g' nejineji.txt | a | sed -Ez 's/ | |\n//g'

この解答だと zshでしか動かないかもなので、bashじゃないとヤダよ!って人はいい感じに書き換えてくださいね

おわり

今回も楽しかったです。Q7は考えすぎのせいかわからないですが体温が高くなっているのを感じました。おそろしいね。 やはりTLに投稿された解答をみて「こういうのもあるのか」と思うのが楽しい部分の一つですね。今回もそれができたのがよかったです。

企画、開催ありがとうございました!

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