日々之迷歩

世の中わからんことだらけ

ITが複雑で難しくなっていく様に翻弄される日々です

「第36回シェル芸勉強会:リモート参加」レポート

シェル芸勉強会に関するブログ記事の記載が滞っていた。 シェル芸勉強会福岡サテライトの開催を予定していたのだが、大阪サテライトで大雨の影響で開催中止の連絡があった。福岡は大丈夫か?と改めて大雨情報を確認するとありゃヤバイ・・・という事で、福岡サテライトも中止の判断。参加予定だった方々、もし良ければ次回に参加いただければと。

大雨の影響は想像以上で、甚大な災害の報道が。自然災害ややっぱり大変なのだ。そもそも自分自身が帰宅難民になりかけてしまい・・・

twitter.com twitter.com twitter.com twitter.com twitter.com twitter.com

勉強会募集サイト

本家東京会場募集

usptomo.doorkeeper.jp

大阪サテライト会場募集

atnd.org

福岡サテライト会場募集

atnd.org

イベント報告関連

今回はみなさんどんな感じだったのかな?

(上田会長による)Togetterまとめ

togetter.com

午前の部

午前の部は不参加。(第一第三土曜日の午前中は会議があるので調整が必要) 鳥海さんによる文字コードの話だったようだ。資料はこちら。

シェルで文字コードに触れてみる 講師:USP友の会 鳥海秀一

午後の部

今回はボッチでYoutube見ながらリモート参加。問題と解答例はこちら。(出題者の上田会長ブログ)

【問題と解答】jus共催 第36回七夕・・・7は素数じゃないですか(しかも2つ)シェル芸勉強会 | 上田ブログ

今回は参加者のフォローとかが無くて落ち着いた感じだったが、問題解くのが難しいのは相変わらず。 処理の内容は思いつくけど実現方法をどうするか?を思いつくのが大変たいへんタイヘン。

Q1

テキストファイル内に隠されたメッセージを読み取る!? 不可視文字を見つけろっていう事だろうか? まずはodコマンドで中身を確認してみる。 odコマンドの-t x1cオプションは、不明なデータを見る時によく使う。

$ od -t x1c welcome.txt | head
0000000  5f  5f  5f  5f  5f  5f  5f  5f  5f  5f  5f  5f  5f  5f  5f  5f
          _   _   _   _   _   _   _   _   _   _   _   _   _   _   _   _
*
0000060  00  5f  5f  00  5f  00  5f  5f  5f  5f  5f  5f  5f  5f  5f  5f
         \0   _   _  \0   _  \0   _   _   _   _   _   _   _   _   _   _
0000100  5f  5f  5f  5f  5f  5f  5f  00  00  5f  5f  5f  5f  5f  5f  5f
          _   _   _   _   _   _   _  \0  \0   _   _   _   _   _   _   _

NUL文字が混入されているっぽいぞ。って事でNUL文字を@に変換してみる。 あとは折り返し文字幅80文字から10文字ずつ減らしながら試して、下記の通り解答完成。 メッセージの作り方は上田会長の問題と解答のページを参照。

$ cat welcome.txt | tr '\0' '@' | fold -w 70 | tr _ ' '
                                                @  @ @                
 @@                           @@@@@@       @@    @@@@@  @             
  @              @              @@         @@ @@@@@      @    @@@     
  @             @@@@@         @@@@@@@      @      @      @  @    @    
  @     @        @@@         @  @@  @      @@@   @@      @@@    @@    
   @@@@@       @@  @@@         @@@@@        @   @@         @          
                                                                      
                                                                      
                                 @                          @@@       
       @ @        @@          @@@@@@                        @@@@      
  @@@@            @@          @@@@@@@          @          @@    @     
@@    @@         @@@            @@@@@          @@@              @     
        @@@     @@  @   @     @@   @@        @@@@              @      
               @@   @@@@       @@@@@        @@@@ @@          @@       
                                                                      
                                                                      
                                                                      
   @@   @     @                                                       
 @@@@@@@ @@    @    @@@                                               
    @  @ @@    @  @    @                                              
   @   @       @@@    @@                                              
  @  @@@         @                                                    
                                                          

Q2

悪質なファイル名を綺麗に整理する実用的な問題!? (こんなファイル名にするなあああああああああああああああとキレそう)

解答としては、下記のようなコマンドを実行すれば良いという事。 このコマンドをどうやって作成実行するか考える問題。

mv 1-B.doc 1年B組.doc
mv 1A.doc 1年A組.doc
mv 3年D組.doc 3年D組.doc
..(省略)..
mv 1ーD.doc 1年D組.doc
mv 1年E組.doc 1年E組.doc
mv 4年C組.doc 4年C組.doc

Macで下記のように考えた。上記のようなコマンド列が出力される。 あとはパイプで| shに渡して実行すれば良い。

# Mac限定。おそらくFreeBSDも可。
$ ls | tr '1-9' '1-9' | tr 'A-Z' 'A-Z' | tr 'a-z' 'A-Z' | sed 's/組\././' | sed 's/\([1-9]\)\(.\)\([A-Z]\)/\1\3/' | sed 's/\(.\)\(.\).*$/\1年\2組.doc/' | paste -d ' ' <(ls) - | sed 's/^/mv /'

しかし残念ながらUbuntuでは上記の解答はダメ。 GNUのtrコマンドはマルチバイト文字に非対応みたいだ、ガーン。

# GNUのtrコマンドは変になっちゃう
$ ls | tr '1-9' '1-9' 
1-B.doc
1A.doc
3999D99?.doc
399999999?.doc
..(省略)..

BSDのtrコマンドやodコマンドは、マルチバイト文字対応しているので便利なのだった。

Q3

これはまず日付の列挙をする必要がある。 色々とやり方はあるが、seqコマンドとGNU dateを使ったやり方はこちら。 まずは下記のような文字列リストを作成する。

$ seq 0 364 | sed 's/.*/20180101 & days/'
20180101 0 days
20180101 1 days
20180101 2 days
..(省略)..
20180101 362 days
20180101 363 days
20180101 364 days

次にGNU dateコマンドに-f -オプションを付けてパイプで渡す。

$ seq 0 364 | sed 's/.*/20180101 & days/' | date -f - '+%Y%m%d'
20180101
20180102
20180103
..(省略)..
20181229
20181230
20181231

あとは2,3,5,7が4つ含まれる行を抜き出せば良い。 awkのgsubコマンドは、正規表現にマッチした回数を返すとのでこんな感じになる。 gsubコマンドは指定した文字列を破壊的に処理するので注意。

$ seq 0 364 | sed 's/.*/20180101 & days/' | date -f - '+%Y%m%d' | awk '{d=$0;if(gsub(/[2357]/,"",d)==4)print}'
20180222
20180223
20180225
..(省略)..
20181223
20181225
20181227

Q4

俳句を考える問題!?というより縦書き処理をしろという問題だ。まずは一句・・・

$ echo -e 'しぇるげいにん\nたなばたなのに\nひきこもり'
しぇるげいにん
たなばたなのに
ひきこもり

ここから縦書きに変換していく。 横書きを縦書きに変換する時は、行を上下ひっくり返した後、行列逆転すれば良い。 という事でtacからのrs -Tを使って処理して見る。 データの数を縦横揃える必要があるので注意。

$ echo -e 'しぇるげいにん\nたなばたなのに\nひきこもり' | awk '{printf "%-7s\n",$0}' | sed 's/ /@/g' | sed 's/./& /g;s/ $//g' | tac | rs -T
ひ  た  し
き  な  ぇ
こ  ば  る
も  た  げ
り  な  い
@  の  に
@  に  ん

あとは短冊に入れれば良いが、準備された短冊ファイルtanzakuを使ってないのでゴメンナサイ。 awkの$1=$1の部分が意味不明に思う人が多いと思うので補足。 OFSで出力の区切り文字を全角空白に指定しているが、これはフィールドの再構築を行わないと適用されない。 そこでパターン部分に$1=$1のような処理を書いて、フィールドの再構築を明示的に指示。

$ echo -e 'しぇるげいにん\nたなばたなのに\nひきこもり' | awk '{printf "%-7s\n",$0}' | sed 's/ /@/g' | sed 's/./& /g;s/ $//g' | tac | rs -T | awk -vOFS=' ' 'BEGIN{print "┏ーー-┷-ーー┓"}$1=$1{print┃ "$0" ┃"}END{print "┗ーーーーーー┛"}' | sed 's/@/ /g'
┏ーー-┷-ーー┓
┃ ひ た し ┃
┃ き な ぇ ┃
┃ こ ば る ┃
┃ も た げ ┃
┃ り な い ┃
┃   の に ┃
┃   に ん ┃
┗ーーーーーー┛

Q5

えー下記のようにrevコマンドを単純に使ってもダメ。 文字列がひっくり返ってるし、馬の顔の輪郭もヘンテコリンになる。

$ cowsay あなたとJava今すぐダウンロード | rev
________________________________ 
> ドーロンウダぐす今avaJとたなあ <
-------------------------------- 
^__^   \        
_______\)oo(  \         
\/\)       \)__(            
| w----||                
||     ||                

色々考えたけどどれも中途半端でダメだった。上田会長の解答を少し解説してみる。 まずは右側に文字を追加して、各行の文字数が並ぶように右端を揃える。

$ cowsay あなたとJava今すぐダウンロード | awk '{printf $0;for(i=length;i<=30;i++)printf "@";print ""}'
 ________________________________
< あなたとJava今すぐダウンロード >@@@@@@@@@@
 --------------------------------
        \   ^__^@@@@@@@@@@@@@@@
         \  (oo)\_______@@@@@@@
            (__)\       )\/\@@@
                ||----w |@@@@@@
                ||     ||@@@@@@

次に左右ひっくり返したものを下に追加する。 上田会長の解答例では、moreutilsのpeeコマンドを使って処理しているが、 同様な処理はteeコマンドとbashのプロセス置換を使っても可能だ。 pee command1 command2tee >(command1) >(command2) >/dev/nullは同等。

$ cowsay あなたとJava今すぐダウンロード | awk '{printf $0;for(i=length;i<=30;i++)printf "@";print ""}' | tee >(cat) >(rev) > /dev/null
________________________________ 
@@@@@@@@@@> ドーロンウダぐす今avaJとたなあ <
-------------------------------- 
@@@@@@@@@@@@@@@^__^   \        
@@@@@@@_______\)oo(  \         
@@@\/\)       \)__(            
@@@@@@| w----||                
@@@@@@||     ||                
 ________________________________
< あなたとJava今すぐダウンロード >@@@@@@@@@@
 --------------------------------
        \   ^__^@@@@@@@@@@@@@@@
         \  (oo)\_______@@@@@@@
            (__)\       )\/\@@@
                ||----w |@@@@@@
                ||     ||@@@@@@

awkで3行目から11行目を抜き出す。 大まかなポイントはここまでだろう。後は細かい処理を頑張るのみ。

$ cowsay あなたとJava今すぐダウンロード | awk '{printf $0;for(i=length;i<=30;i++)printf "@";print ""}' | pee cat rev | awk 'NR<4||NR>11'
 ________________________________
< あなたとJava今すぐダウンロード >@@@@@@@@@@
 --------------------------------
@@@@@@@@@@@@@@@^__^   \        
@@@@@@@_______\)oo(  \         
@@@\/\)       \)__(            
@@@@@@| w----||                
@@@@@@||     ||                

Q6

素数のみを丸囲み文字にする問題。16進数に変換してxxdで処理とか考えたけど時間切れ。

上田会長の解答例以外だと、下記の解答例がシンプルだ。 printfの出力フォーマットで%cを使えばよい、なるほろ。

twitter.com

$ seq 20 | factor | tr -d ":" | awk '$1==$2 { printf("%c\n", 9311+$1)} $1!=$2 {print $1}' | xargs
1 ② ③ 4 ⑤ 6 ⑦ 8 9 10 ⑪ 12 ⑬ 14 15 16 ⑰ 18 ⑲ 20

Q7

テキストファイル内に隠された、謎のバイナリデータを探す問題。

下記はMac限定の解答。BSDのtrコマンドがマルチバイト文字に対応してるので。 あとnlコマンドの練習も兼ねて。

$ cat text | tr -d '[:print:]' | cat -v | nl -ba
     1  ^@
     2  
     3  
     4  
     5  ^B
     6  
     7  
     8  ^F
     9  
    10  ^V
..(省略)..

Q8

Sortware Designで連載中の「シェル芸人の挑戦状」から、更に上級問題。 会長の解答例を参考にして頑張ってくれたまえ・・・ mecabを使ってからの、縦書きを横書きへ変換してからの・・・・

全体を通して

今回も相変わらずの問題?だったが、毎度の事ながら問題作成されている上田会長お疲れ様である。 大雨によりサテライト会場が大阪・福岡共に開催出来なかったのは残念だった。 福岡へ参加予定だった方は、初めての参加者も多かったようで。 次回もし予定が合えば、よろしくお願い申し上げる。

福岡で独自に初心者向けを開催したい。プライベートやお仕事面で今は余裕が無く、なんとかしたい。