17歳からのプログラミング入門。

情報系の門の先で起きたことをたまにメモ。

echo 学生セキュリティ勉強会 | sed 's/.*/sed計算機/'

前置き

9/23(土)、秋葉原カスペルスキーさんで『第一回 学生セキュリティ勉強会』というイベントに参加してきました。

参加者は40人程度、部屋は満員で、主催者も驚いていたようでした、し、いるやんもびっくりでした。

本会の内容は、セキュリティに関する話ということで言わないように釘を刺されているので触れられません、ごめんなさい。 言える範囲としては「SQLインジェクションXSS等の基本的なWeb脆弱性の体験と解説」(イベントページより)ということで、全く攻撃を行ったことがない初心者にとっては(脆弱性に対する考え方も含めての)学びがある良いイベントだったのではないかと思ったのでした。

懇親会(本会)

17:30くらいから懇親会が始まりました。時間は1時間くらいということで、カスペルスキーさんのご厚意のピザを頬張りながら交流を楽しみました。

ただまあ、人が集まるとLTしたくなるのが芸人の性というもので、何故かセキュリティ勉強会でシェル芸とsedの発表をしてしまいました。 発表では不明瞭な点もありましたので、以下にまとめなおして振り返りとさせていただきます。

シェル芸とは?

  • 「マウスも使わず、ソースコードも残さず、GUIツールを立ち上げる間もなく、あらゆる調査・計算・テキスト処理をCLI端末へのコマンド入力一撃で終わらすこと。」
    • 重要な(繰り返し使いそうな)操作ならソースコードに残しましょう、そうするべきだなーとシェル芸しながらつくづく思います・・・。
    • 人々は楽しみでこれをやっているのです。
  • シェル芸勉強会というのがあります。

シェル芸の例題紹介

  • contents.texについて、「\begin{figure}と\end{figure}」で囲まれた部分を全て抽出してください。(シェル芸勉強会 vol.28 Q1より)
    • sedというコマンドの検索機能を使うと、汎用プログラミング言語で解くより遥かに簡単に解けます。
    • 解答は公開されているので、いるやんの解答を書いておきます。
    • sed -n '/\\begin{figure}/,/\\end{figure}/p'
    • 「いらないところは表示しない、 “\begin{figure}” を見つけて、 “\end{figure}” が見つかるまでの範囲を表示して」と読みます。
  • 他にも、grepを使うとさくっと解けるvol.30 Q1を紹介しました。

(GNU) sedについて

  • sedはエディタです。(Stream EDitorの略、manにもそう書いてある)
  • リッチなエディタを立ち上げなくても、コマンド"ライン"上で検索・置換・追加(これはほとんど使われない)といった操作ができます。
  • sedでは数値の計算が行えません。
    • awkとかを使うのが一般的かなーって。

sedで足し算作った(本題)

LISPっぽい足し算を行ってみました。

echo '(+ 4 7)' | sed -E 's/\(\+ ([0-9]) ([0-9])\)/\1\2/;y/123456789/abcdefghi/;s/.$/\U&/;tadd;:add;s/(.)X/1\10/;s/(.?)0(.?)/\L\1\2/;tendadd;y/abcdefghiABCDEFGHI/0abcdefghBCDEFGHIX/;badd;:endadd;y/abcdefghi/123456789/'

これ1行をbashに貼り付けてもらうと11と表示されます。 実際、 (+ 1 1) -> 2 のような変換を100個くらい書けばできるんですが、それじゃ味気ないよね、と。

プログラムの解説

1行で書くのは読みにくいだけなので、主にセミコロンごとに改行して1行ずつ読み下していきましょう。 nlコマンドを使って行番号を振ってみました。

     1   echo '(+ 4 7)' |
     2  sed -E '
     3  s/\(\+ ([0-9]) ([0-9])\)/\1\2/;
     4  y/123456789/abcdefghi/;
     5  s/.$/\U&/;
     6  tadd;
     7  :add;
     8  s/(.)X/1\10/;
     9  s/(.?)0(.?)/\L\1\2/;
    10  tendadd;
    11  y/abcdefghiABCDEFGHI/0abcdefghBCDEFGHIX/;
    12  badd;
    13  :endadd;
    14  y/abcdefghi/123456789/
    15  '

[string]という形式でその時点での文字列を表示することとします。 また、以後で _ は何かのパターンを表します。 _ という文字そのもののつもりではないことを認識してもらうとともに、正しいパターンの書き方は↑のコマンド列に記されていることをご確認ください。

  1. (+ 4 7) という文字列を後続のコマンドに渡します。
  2. [(+ 4 7)] 後続のコマンドはsedです。拡張正規表現(sed内部でのバックスラッシュのルールが変わります)を使用します。
  3. [47] sコマンドは s/pattern/str/ の構文で patternstr に置換します。今回は (+ _ _) の形式の文字列のアンダーバーの部分を取り出して、それを繋げた文字列に置換します。_ はいずれも1文字の数字を表します。
  4. [dg] yコマンドは逐語変換と言って、左側の文字を対応する右の文字に変換します。 1a に、 2b に、・・・と言った具合です。 4d に、 7g に対応します。
  5. [dG] 末尾の1字を大文字に変換します。
  6. [dG] 実はsedのコマンドにはC言語のようなラベルジャンプ機能があります。tコマンドは直前のtコマンド以降(なければプログラム開始以降)にsコマンドが成功していれば、指定のラベルにジャンプします。 add ラベルは7行目にあるので、6行目は単純に以前のsコマンドの成功をリセットしているだけです。
  7. [dG] :コマンドはラベルの定義です。 add というラベルを定義します。
  8. [dG] _X の形式の文字列を 1_0 という風に置換します。今回は X がないので置換に失敗して、文字列はそのままです。
  9. [dG] _0_ の形式の文字列からアンダーバーの部分を取り出して、それを繋げた文字列に置換します。今回の _ は数字でなくてもいいし、存在しなくてもいいです。ちなみに今回は 0 がないので置換失敗です。
  10. [dG] 8-9行目で置換に成功していれば endadd というラベルにジャンプします。今回はどちらも失敗しているのでそのまま素通りします。
  11. [cH] 逐語変換です。前の文字を1文字若くして、後ろの文字を1文字老かせます。
  12. [cH] bコマンドは無条件ジャンプです。アセンブリで言うところのbranchに相当するのでしょうか。7行目の add ラベルまでジャンプします。

これ以降の7-12行目の動きは3度ほど上と同じ操作を繰り返し、 [cH] から、 [bI][aX] となって7行目から説明を再開します。

  1. [aX] add ラベルにジャンプしてきました。
  2. [1a0] _X の形式の文字列を 1_0 に置換します。 _ にはaがマッチして 1a0 という文字列になります。
  3. [1a] _0_ (ただし _ はなくても良い)の形式に a0 の部分がマッチして、 a のみに置換されます。 1 はそのまま残るので、 1a となります。
  4. [1a] 8行目で置換に成功しているのでtコマンドが発動して、13行目の endadd ラベルまでジャンプします。

13行目以降は計算終了処理が続きます。

  1. [1a] endadd ラベルを定義します。飛んできました。
  2. [11] 逐語変換で、アルファベットを数字に戻します。
  3. [11] sedコマンドはここまでで、この状態の文字列として4+7の答え 11 が出力されます。お疲れ様でした。

今後の展望

  • 複数桁の足し算もやってみたいです。愚直にやればできるんですが、桁上りのスマートな解決に悩んでいます。1桁ずつ切り出して計算を行う方法はできることを確認済みです。
  • 1桁同士であれば引き算は簡単なんじゃないかと思ってます。足し算よりコード短くなりそう。
  • sedの知識の更なる拡充
  • そもそもこんなふざけた計算機はもう作りたくないです💢

おわりに

危険シェル芸は手元では絶対実行しないようにしようね! 誰が書いたかわからないシェルコマンドが落ちていても実行しちゃダメだぞ!中に何が書かれているかは確認できる範囲で確認しよう!

保健室の先生とお話してきた。

表題の通りです。

なんとなく書き付けておきたかったので、話し始めだけ書き付けています。

お悩み相談の入り口でしかないので、メッセージ性があったりするわけでもないです。

 

続きを読む

プログラマの端は書き捨て。

kosen13s' Advent Calendar 2016 (http://www.adventar.org/calendars/1855) の 3 日目の記事です。

これは供養です!

先日、半年ほど使っていた Xubuntu 15.10 の仮想マシンに別れを告げ Xubuntu 16.10 に乗り換えたのですが、 前のディスクの tmp ディレクトリに大量のプログラムが書き捨てられていました。

f:id:Iruyan_Zak:20161203234928p:plain

人からの相談や、耳にした tips などを tmp に投げ入れているため、 もう用のないコードではありますが、もしかしたら誰かの知見になりうるかと思うので、公開します。

ただし、本当に意味のわからないコードもあるので、紹介するのは一部だけです。

/0523

C++ の deprecated を用いたコンパイル時型表示のプログラムです。

#include<bits/stdc++.h>
class H{};

template <class T>
[[deprecated]] void chk_type(T t){}

int main(){
    auto cache = new std::unordered_map<int, std::weak_ptr<const H>>;
    chk_type(cache);
}

これをコンパイルすると

a.cpp: In function ‘int main()’:
a.cpp:10:19: warning: ‘void chk_type(T) [with T = std::unordered_map<int, std::weak_ptr<const H> >*]’ is deprecated [-Wdeprecated-declarations]
     chk_type(cache);
                   ^
a.cpp:6:21: note: declared here
 [[deprecated]] void chk_type(T t){}
                     ^

このような警告が出て、 cache の型の推論結果が表示されます。 一節には、そこらの IDE では推論できない推論結果まで教えてくれるらしいです。

/0830

https://speakerdeck.com/greymd/mei-ri-kou-keru-sieruyun-wojue-eyou?slide=31 これで遊んでた時の残骸だと思う。シェル芸いいよ。 xaa ってこれわけわからずに split 打った出力だよなあ。

% ls 0830
fuga  hoge  holidays  xaa

あと、同時期に "man コマンドクイズ" ってのにもはまってました。

man vim を実行すると vim - Vi IMproved, プログラマのテキストエディタ と表示され、 vim はエディタであるとわかるのですが、 man emacs を実行すると emacs - GNU project Emacs と表示され、「EmacsEmacsだ」という強い意志を感じることができます。

/0904

C++ラムダ式は関数ポインタに突っ込めるんだなあ・・・。 これで最適化を封じて時間計測する、みたいな技があると聞いた気がする。

#include<iostream>
using namespace std;

int main(void){
    int (*hoge)(int) = [](int n){ return n*n; };
    cout << hoge(10) << endl;
}

/0921

mkfifo ってコマンドを使うと名前付きパイプっていう面白いファイルを作ることができます。 もしかしたら環境によってコマンド名は違うかも。

% ls 0921
echo hello  fifo|  hello@  p|  preprocess.c

何ができるかは説明すると長くなるんだけど、2つのプロセスからこのファイルへの書き出しと読み出しが両方行われた時に初めて、2つのプロセスに書き出しと読み出しを行わせる(それまではブロックする)っていう挙動をします。

何に使えるかわからん。

/1024

やさしい C のポインタのお話。 言いたいことはすべてコメントになってる。

#include<stdio.h>

int main(){
    char h[4];
    h[0] = 1;
    h[1] = 2;
    h[2] = 3;
    h[3] = 4;

    // ポインタなんて所詮整数だからビット演算にかけられたりするよ
    printf("%p, %zu\n", h, (size_t)h);
    printf("%d\n", *(char*)((size_t)(h+3) & (-4)));

    putchar('\n');

    // ポインタなんて所詮その変数が格納されている"先頭の"アドレスでしかないから、サイズの違う型のポインタにキャストしてやればもともとの変数の境界なんてうやむやにできるよ
    *((short*)h+1) = *(short*)h;
    for(int i=0; i<4; i++) printf("%d\n", h[i]);

    putchar('\n');

    // short はここでは 2 バイト整数型として、それらを 1 バイトずつ表示。リトルエンディアン方式により下位のバイトが先行するのが見える
    short a = 258;
    printf("%d, %d", *(char*)&a, *((char*)&a+1));
}

この話を後輩に面白く話せるようになれたらいいなあ。 このコードが欲しければ好きに持って行ってください。

/1119

split コマンドの挙動を調べたくなったので、 sudo apt-get source coreutils してソースを拾ってきました。

いろんなコマンドの実装が読めて楽しいです。

% ls 1119
coreutils-8.23/                  coreutils_8.23-4ubuntu2.dsc  hgoe   xaa  xac
coreutils_8.23-4ubuntu2.diff.gz  coreutils_8.23.orig.tar.gz   pipe/  xab  xad

あとがき

思ったより何書いてるかわからないものが多くて抜粋に苦労しました。 広く浅く、いろんな言語、いろんな分野をやっているので、 面白い tips をご存じの方はぜひ教えて下さい!

#mixi_git challenge に参加した話

ざっくり言うと

mixi さん主催の git イベントに、 同じ学校の人(以下ペアの人)に誘われて行ってみたら、 1位タイになってしまったお話

です。

続きを読む

コンマ以下に生きる人のためのかっこいい時計のご紹介

おはようございます。 朝です。気づいたら朝です。

今日でインターンシップに来てから3週間になりますが、今日ももれなくお仕事です。 職場で寝てしまっても優しく布団をかけてくれる社員さんがいることを願っています。


さて、今日は、時の流れを感じられる、おしゃれな時計のご紹介です。

f:id:Iruyan_Zak:20160909064732g:plain

良いですよね、良さを感じますよね、ね? デスクトップにおいておくだけでいつでも時間に追われる感覚を味わえます。

・・・え?そんなことはいいから早く作り方を教えろって?

わかりました。 以下がプログラムです。bash上で動作しています。

#! /bin/bash

while true
do
# sleep 0.32
echo -ne \\r$(date +%T.%N)
done

ね、簡単でしょ? 一応説明しておきます。

  • while true
    while は、後続のコマンドが 0 (真)を返し続ける限り、 dodone に囲まれた内容を実行します。
    true は、すぐに 0 を返すだけの何もしないコマンドです。
    よってこれは無限ループを表します。
  • echo -ne \\r
    echo は引数をすべて(オプションを除く)標準出力に吐き出します。
    -n のオプションは、出力後に改行を行いません。
    -e のオプションは、エスケープシーケンスの出力を有効にします。
    \\r 、すなわち '\r' は、キャリッジリターンと言って、カーソル位置を行頭に戻します。
    よって、ここまでで、「出力を同じ行の行頭から流すことで書き換えを実現」したことになります。
  • $(date +%T.%N)
    $(command args) は、 command args を実行した時の標準出力に置き換えられます。
    例えば、 echo $(echo hoge) は、
    $(echo hoge)echo hoge の標準出力 hoge に置き換えられ、
    結果として全体は echo hoge と等価になります。
    今回は $(date +%T.%N)date +%T.%N の標準出力に置き換えられます。
    date コマンドは、現在の時刻を表示したり設定したりできるコマンドです。
    + で始まるフォーマット指定文字列を引数に与えてあげると、現在の時刻の表示方法をカスタマイズすることができます。
    今回は +%T.%N なので、 HH:MM:SS.mmmμμμnnn という形式で時刻を表示してくれます。

つまり、無限に同じ行に時刻を吐き出し続けることでめまぐるしく変わるナノ秒単位の時計を実現している、ということなのです。(実際ナノ秒までの精度はないはず)

ところで、お察しの通りめちゃくちゃ重いです。無限ループ回してますからね。 ということで、コメントアウトしている sleep コマンドを挿入することで、処理回数を減らすことができます。 かっこよさは少し減りますが、CPU使用率は結構削れます。

それでは、良いシェルライフを!

Git入門したい!

先日の記事に不適切な表現が含まれていたので、書き直します。


7/8、 "Gitって何?見習いプログラマのためのGit入門会" というイベントに、メンターとして参加してきました。

続きを読む

WordCamp Kansai、ですって!

こっちは元気な話題です。

7/10、"WordCamp Kansai"に参加してきました。

会場の大阪大学には昔行ったことがあるので、地図を開くことなくたどり着くことが出来た辺りから気分が良いです。

僕が参加したハンズオンは2つあります。

続きを読む