日々之迷歩

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

ITが複雑で難しくなっていく様に翻弄される日々です。微力ながら共著させていただいた「シェル・ワンライナー160本ノック」をよろしくお願い申し上げます。

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

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

問題作成と解説の上田さん、ありがとうございます。参加者の方々もお疲れ様でした。

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

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

勉強会の情報

勉強会主催者上田さんが公開されているリンク集をご覧ください。

b.ueda.tech

午前の部

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

午後の部

今回はボッチでYoutube見ながらリモート参加でした。

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

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
..(省略)..

macOSやFreeBSD付属の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コマンドは指定した文字列を破壊的に処理するので、$0の内容を変数dに代入して処理しています。

$ 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を使って処理することを考えます。 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----||                
||     ||                

色々考えたけどどれも中途半端でダメでした。 出題者上田さんの解答例では、右側に文字を追加して各行の文字数を揃えた後でrevを使う方法でした。

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

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

下記はmacOSやFreeBSD限定の解答です。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を使ってからの縦書きを横書きへ変換してからの・・・・という感じでした。

全体を通して

大雨によりサテライト会場が大阪・福岡共に開催出来なかったのは残念でしたね。 福岡サテライトの参加予定者は初めての方も多かったようなのですが、次回もし予定が合えばご参加よろしくお願いいたします。 福岡で独自に初心者向けを開催したいですが、プライベートやお仕事面で今は余裕が無く、なんとかしたいです。