たにしきんぐダム

プログラミングやったりゲームしてます

readコマンドで 矢印キー や Ctrl+x などの入力を読み取る

この記事は CAMPHOR- Advent Calendar 2015 の2日目の記事です.

シェルで標準入力を読み取るコマンドといったらreadコマンドがあります.

readの概要

read Man Page | Bash | SS64.com

readコマンドはシェルの組み込みコマンドで 標準入力を読み取り 改行文字までまたはEOFまで読み込み、 引数に変数が指定されていた場合は入力値をその変数に格納します.

readコマンドの区切り文字はシェル変数である$IFSに格納されている文字が利用され、引数に複数の変数が指定されていた場合は指定された区切り文字で区切って変数に格納されます.(デフォルトでは$' \t\n' スペース・タブ・改行文字)

ちなみに入力の区切り文字は\を頭につけることでエスケープすることができます. 便利っちゃ便利だけど\がエスケープ文字として解釈されてしまうので不便だったりする(これは後述の-rオプションで解決します)

readオプション

上記のman pageを読めば分かりますがよく使うオプションとしては以下のようなものがあります.

  • -n<nchars>
    • 普通は改行文字もしくはEOFを読むまで入力を読み取りますが、このオプションをつけることでnchars文字数だけ入力読み取ったらRET入力を自動的に読み取り、入力待ちを終了させます.
  • -r
    • 上記で述べたように区切り文字は\でエスケープできますが-rオプションをつけると、\はエスケープ文字として機能しなくなりそのまま読み取られるようになります.
  • -s
    • 通常はreadコマンドで入力を読み取るとき ユーザーが入力した文字は画面に表示されますが-sオプションをつけることで入力は表示されなくなります.パスワードの入力を要求するときとかに便利です.
  • -t<timeout>

IFS=

区切り文字に空文字を代入しています.これにより スペース・タブ・改行といった特殊文字が区切り文字として機能しなくなるため空白文字などをそのまま入力値として読み取ることができるようになります.

これで\なんかで区切り文字をエスケープしなくてもそのまま受け取ることができるようになります.

注意 $IFSの値をいじくるのはIFS= read xxxという感じにコマンドの直前につけてコマンドと一緒に実行したり、書き換えたら後で元に戻すなりするようにしましょう. 環境変数書き換えることになるので大変なことになりそう.

一文字ずつ読み取って逐一処理する

RETの入力なしに一文字入力を読み取って その入力値に沿って処理を行うというプログラムが書きたい場合、以下のような感じになります.

例えばキー入力でのカーソル移動、vimっぽくj,k,h,lの入力を読み取ってtput cuu1とかでカーソルを移動させたいときに使います.

while IFS= read -r -n1 -s char; do
  case $char in
    j)...;;
    ...
  esac
done

一文字しか入力しないのでIFS=とか-rは要らない気もしますがこんな感じでいけます.

特殊文字の検知

通常の文字は上記のようなやり方で入力を読み取ることができます. では特殊文字などはどうやって読みよればいいのだろうか...

man bashを見ると以下のような記述が有ります. $'string' のstring部分に以下に指定されているような文字を入力すると ANSI C standardの文字に変換されるようです.

Words of the form $'string' are treated specially.  The word expands to
string, with backslash-escaped characters replaced as specified by  the
ANSI  C  standard.  Backslash escape sequences, if present, are decoded
as follows:
       \a     alert (bell)
       \b     backspace
       \e     an escape character
       \f     form feed
       \n     new line
       \r     carriage return
       \t     horizontal tab
       \v     vertical tab
       \\     backslash
       \'     single quote
       \nnn   the eight-bit character whose value is  the  octal  value
              nnn (one to three digits)
       \xHH   the  eight-bit  character  whose value is the hexadecimal
              value HH (one or two hex digits)
       \cx    a control-x character

\xHH the eight-bit character whose value is the hexadecimal value HH (one or two hex digits)

とあるようにascii codeの16進数表記で特殊文字なんかも検知できそう.

(例えばaのasciiコード16進数は61なので$'x61'aの入力を読み取ることができる.)

Extended ASCII in ANSI C

standard ASCII CODE はそもそも7ビットコードでありコード表を見てもCtrl+xArrow keyなどは見当たりません.

あとで8ビット文字コードが主流になってきたとき 8bit を使って残りの128文字にみんな好き勝手な文字を当てはめていきASCIIを拡張してきたっぽい

そのようないろんな拡張ASCIIのうち有名なのがOEM Extended ASCIIANSI Extended ASCII らしい

(参考: Ascii Codes - C++ Tutorials)

bashでは ANSI Extended ASCII のほうに変換されるっぽいですね.

Ctrl+xなどの入力

\cx a control-x character とあるようにCtrl+x などの入力は$'\cx'などで読み取ることが出来ます.

せっかくなので先ほどの拡張ASCIIを使って読み取ってみると,Ctrl+xascii code 16進数表記は24なので$'\x24'で読み取ることができます.

  case $char in
    $'\cx'|$'\x24')...;;
    ...
  esac

矢印キー(Arrow key)の読み取り

矢印キーの ascii code

先ほどの拡張ASCIIコード表の上矢印(Up Arrow)をみてみると0;72とあります.なんだこれ???

よくわからないので矢印キーの asciiコード16進数表記を調べてみましょう. 入力の16進数変換にはxxdhexdumpコマンドが便利

Arrow keyの入力値をreadで読み取りその入力値を16進数変換して表示してみます.

read key; echo "$key" | hexdump

このコマンドを入力したあとにUp Arrow(上矢印)を入力すると1b 5b 41というような結果が得られます. どういうことかというとUp Arrow(上矢印)の入力は1b 5b 41という3つのascii codeの入力によって実現されてるっぽいです.

矢印キーの読み取り

  case $char in
    $'\x1b\x5b\x41')...;;
    ...
  esac

という感じで読み取ることができる.

1文字ずつ読み取ってる場合はどうするんだよ!というのがありますが、僕は以下のような感じで一文字目が$'\x1n'(エスケープ文字)だった場合はあと2文字くらい入力が起こってそうだから追加で2文字読み取って$charに追加するみたいな感じでいきました.

  while IFS= read -r -n1 -s char; do
    if [[ $char == $'\x1b' ]]; then
      read -r -n2 -s rest
      char+="$rest"
    fi

最後に

こんな感じのことを使ってニコニコ動画をターミナルから検索できるnicotermとかいうCLIクライアントを作りました.

使い方は簡単でコマンドの引数に検索クエリを入力するだけ オプションつければソート順も変更できるし カーソル位置でoとかでサクッとブラウザで動画開けたりして便利

github.com

https://gyazo.com/8334764edfb2c1ec9e9beca21d64b2af

まとめ

今回bashでの解決策について記事を書きましたがbashじゃなかったらどんな感じになるんだろう...

readでの読み取り以外でも役に立つことも多いかと思う...のでキー入力読み取りについてこの記事が助けになればという感じです.

この記事は CAMPHOR- Advent Calendar 2015 の2日目の記事です.

明日はyaitaimoです!

参考

はてな×ドワンゴ合同ハッカソン@京都 に参加してきました!

先日開催された はてな×ドワンゴ合同ハッカソン@京都 に参加してきた!

dwangohatena.connpass.com

お弁当もお菓子も飲み物も懇親会も無料だし 楽しかったし最高な感じでした

作ったもの

github.com

ニコニコ動画の検索をターミナルから出来る nicoterm というものを作ってみました.

(シェルスクリプトをがっつり(?)書くの初めてでだいぶアレな感じ...)

この nicoterm まだプロトタイプ程度の完成度で色々と追加したい機能があるので そこらへん整備したらまた改めて発表しようかと思っています. (コードもリファクタリングしないと見せられたものじゃないので...)

作るものを決める

ニコニコの検索APIを使って コマンドラインからニコニコ動画を検索できるCLIクライアントでも作るかぁという感じにしました. (クソザコなのではてなの認証をコマンドラインからうまいこと行うやり方が分からなかった...)

コンテンツ検索APIドキュメント

使う道具を決める

コマンドラインツールを作るのだから golang とか使えれば良かったのですが golang 全然触ったことなかった & そんなに難しいコードにはならないかなと思ってシェルスクリプトで書いてみることにしました.

シェルスクリプトは ループの仕方や関数宣言も怪しい感じでしたがググれば何とかなるやろという感じでした. 結果的には勉強になって良い体験になった気がします.

実際に作る

周りでは結構チーム開発したりしてたけど 僕は特に友達と参加というわけでも無かったのでボッチでやりつつ 同じテーブルになった人とかに進捗聞いたりしてワイワイ開発してました.

隣のチームがドローン飛ばしたりしてて激しい感じだった(結局ドローンは使ってなかった)

発表

5分程度で成果物を発表しました.

「ターミナルからニコニコ動画検索したいですよね」という出だしで適当に発表した. あんまり人前で成果物を発表するのに慣れてなかったのですごく簡単な紹介しかできなかったのですが もっと準備して詳しく説明できれば良かった...

他の人の発表

  • はてなブックマークの未読を無くすアプリケーション
  • はてぶのコメントを画面上に流すアプリ
  • ニコニコのコメントのみからその動画を当てるクイズアプリ
  • ニコニコ静画から機会学習を使って俺の嫁探しできるアプリ
  • ツイッターの友達のはてなブックマークから友達がどんな記事を読んでるか分かる便利アプリ

などなどありました. 皆ユーモアも技術力もある作品作ってて面白い! 自分ももっと面白いものを作りたい!

まとめ

他の参加者の方だけでなく はてなドワンゴのエンジニアの方ともかなり交流できて凄く楽しかったです! またこういうハッカソンがあったら是非参加したいです.

主催である はてなさん・ドワンゴさん ありがとうございました!

PyCon JP 2015 に参加してきました!

10/9 ~ 10/12 に開催された PyCon JP 2015 (PyCon JP 運営 — PyCon JP) に参加してきました 10/9 はチュートリアル 10/10, 10/11 に講演等があり 10/12 に開発スプリントという感じで 僕は10/10 ~ 10/12 で参加してきました.

まとめ記事

すでにTogetter や スライド, flicker が公開されているので そちらを見ると雰囲気がつかめるかと思います.

カンファレンス一日目

午前

基調講演を聞いたあとは とりあえず企業ブースを適当に回ったり 無限コーヒーを飲みながら久しぶりに会った大学の先輩と話したりしてた

その後は プレゼンテーション:Python と型ヒント (Type Hints) | PyCon JP 2015 in TOKYO を聞いて型型言ってたりしてたら午前の部が終わり

お昼ご飯は PyCon JP さんが用意してくれたお弁当屋さんの弁当を外の講演のベンチで食べながら次の講演はどこ見に行くかとか話してた

IMG_0191www.flickr.com

ガパオご飯とグリーンカレー食った

午後

食後の眠気と端末の充電したさからソファに座って充電しながら先輩とAndroidの話をしてたらスタッフに写真撮られてた(Pythonの話してなくてごめんなさい) そのままブースを見たりコーヒーを飲んでたらコーヒーブレイクへ お菓子がめちゃくちゃ美味かったです.

その後は プレゼンテーション:tse - Pythonによるテキスト整形ユーティリティ | PyCon JP 2015 in TOKYO を聞いてPythonワンライナー機運を高めたりしてた便利そう

そんなこんなしてるうちにLTの時間に

その後はパーティー! IMG_7185www.flickr.com

知り合いとばっかり話してたし楽しかったけど もっと色んな人と交流すれば良かったなぁという感じです(LTとかできたら話すネタにもなったんだろうけどネタがない…)

カンファレンス二日目

午前

基調講演を聞いた後は適当にジョブフェアーの発表を聞いたり ポスターセッション見たり コーヒー飲んだり

pyexperiment っていう研究用ライブラリが便利そうだなって思った 研究でPython使うようになったらお世話になるかもしれない duerrp/pyexperiment · GitHub

そしてそのままランチタイムへ 二日目はシリアンライス食った

午後

またもや食後の眠気からコーヒーを飲みつつ休憩してた(オープンスペースとかで面白イベントやってたらしいし行けば良かった…) 眠気がとれたら プレゼンテーション:uWSGI/Dockerを利用したWebサービス運用事例 | PyCon JP 2015 in TOKYO を聞いて uWSGI と gunicorn の比較とか聞いて良い知見を得ていた.

その後はコーヒーブレイクだったのですが NOC(Network Operation Center)見学ツアー をやっていたので見学してきました. ネットワーク監視のあれこれを聞いたり 人がよく通る箇所は床ではなく天井に這わしてやるとか細かいところまで考えた配線技術は素晴らしいなあと思いました.

その後は遅れてコーヒーブレイクをとって プレゼンテーション:PyPIデビュー 2015 | PyCon JP 2015 in TOKYO を聞いたりした 僕も便利ライブラリ作りたいです.

その後のLTでは pysqldf とか便利そうだな〜 って聞いてた SQLおじさん見習いとしても pandasをSQLで操作する芸を身につけていきたい

github.com

モノタロウ楽しそうな会社ですね

クロージング

いよいよクロージング モノタロウ侍君とじゃんけんして勝ち残ったら商品が貰えるみたいなイベントがありましたが全然勝てませんでした… (PyCharm Pro とか iPad もあったしすごい)

IMG_7577www.flickr.com

開発sprint

ドキュメント翻訳したいとは思っていたけれど sphinx分からないし…という感じだったので 何も分からないにも関わらずsphinxチームに加えさせて頂いてsphinx環境を作ったり入門したりしてた (ありがとうございました) transifex の Django ja チームに加えて頂いたので翻訳頑張るぞ!

まとめ

  • ネットがめちゃくちゃ安定してるし 常にスタッフがそこらへんにいて安心だった (おつかれさまでした!)
  • 電源確保が難しい
  • モノタロウ侍かわいい…
  • YAPCと比べて大人しめな感じがした 会場の雰囲気も落ち着いた感じで良かった
  • ご飯が美味しかった
  • 結構海外からの方が多かったけどだいたい日本語ペラペラだった. もっと国際交流したい

来年もっと強くなって行きます!!!

英和辞書検索をポップアップからシュッと出来るChrome拡張作った

概要

辞書検索Webアプリとか Chrome拡張とかあるけど

  • そのWebページにアクセスしなくちゃいけなかったり
  • Chrome拡張からの検索結果が新しいタブで開かれたり
  • 調べたい単語を選択状態にしなくちゃいけなかったり

とイマイチ使い勝手がよいものが無かったので ChromeExtensionのポップアップの部分で検索・検索結果の閲覧が出来る感じのChrome拡張を作った.

こんな感じ Gyazo

ボタンがあるけど普通にフォームに検索したい英単語を入力してEnterキー押せば検索結果が出るのでサクッと辞書検索できます.地味に便利.

インストール

Chromeウェブストアにアップロードしてあります. インストールはこちらからどうぞ.

chrome.google.com

GitHub

tanishiking/dejizo-eiwa-chrome · GitHub

注意

現状 英熟語の検索はできないっぽい

この拡張機能のバックエンドには デ辞蔵 REST版API の無償公開版を利用しています.

無償公開サービスのURLです。365日24時間動作していますが稼働保証はございません。

このため この Dejizo Eiwa Chrome も稼働保証はございません. ご了承ください.

PHP でジェネレータを作ったり遅延評価してみる

ジェネレータを作ったり遅延評価するのが流行っているようなので、PHP5.5.0から導入されたジェネレータを使って同様のことをPHPでもやってみようと思いました。

PHPイテレータ、ジェネレータ

PHP 5 は、foreach のような反復処理を可能とするよう オブジェクトを定義する手段を提供しており、IteratorIteratorAggregateなどを実装することによってオブジェクトの反復処理の方法などを細かく指定することができます.

ジェネレータ

先ほど述べたインターフェースを実装することによって反復処理を可能とするオブジェクトを実装することもできますが、ジェネレータを使えば簡単に実装することができます.

早速いくつか簡単なジェネレータを実装してみます。

以上のように内部ではcurrent()メソッドで現在自身が保持している要素を出力し、nextメソッドで次の要素に進むということをしているのですが、同様の処理をforeachで行うことができます.

以下はフィボナッチ数列を無限に返すジェネレータです.

遅延評価

PHP で yield を使ったジェネレータを作成すると遅延評価されていることはこれまでの例から分かることと思います. イテレータを引数にとってイテレータを返す関数を利用することで, より複雑な処理を行うことができます. このようなイテレータを生成する関数はPHP には標準では存在しません. (lstrojny/functional-php · GitHubnikic/iter · GitHubのような外部ライブラリは存在しますが…)
それらの関数を模倣してみます.

実際の例は以下

PHPではデフォルトではリストを受け取ってリストを返すarray_map() やarray_fileter() などは存在しますが、イテレータを受け取ってイテレータを返すようなmap, filter などが存在しないので3~27行目で独自に簡易的に実装しています.