2018年9月29日土曜日

TukubaiのMapを使ってみた

手元のデータをKeynoteのグラフ描画のデータに流し込むために表の形式に整形しようと思ったところ、1ツイートに収まらないくらい長く書いてしまいました。そこで

というツイートをしたところ、@papiron さんから

ということでTukubaiのmap を教わったのでTukubaiを良く知らないということの自戒を込めて使ってみました。ちなみにこの原稿はJupyter Notebookbash_kernelを使って書いています。

環境は以下です。

In [1]:
which map
/usr/local/bin/map
In [2]:
map --help
Usage   : map       [-<l>] num=<n>x<m> <file>
        : map +yarr [-<l>] num=<n>x<m> <file>
        : map +arr  [-<l>] num=<n>x<m> <file>
Option  : -m<c>
        : -n
Version : Sat Dec 10 21:04:17 JST 2011
          Open usp Tukubai (LINUX+FREEBSD/PYTHON2.4/UTF-8)

基本的な使い方

Tukubaiの基本的な使い方は、

"縦のキー" "横のキー" "データ"

となっているデータを適切な表の形式に整形する、というもののようです。

In [3]:
map num=1 << EOF
1 A hoge
1 B fuga
2 A piyo
2 B pohe
EOF
* A B
1 hoge fuga
2 piyo pohe

欠損しているデータがある場合はデフォルトだと0が与えられます。

In [4]:
map num=1 << EOF
1 A hoge
1 B fuga
2 A piyo
2 B pohe
3 A fugaa
EOF
* A B
1 hoge fuga
2 piyo pohe
3 fugaa 0

欠損データのデフォルト値は -m オプションで指定することができます。

In [5]:
map -m なし num=1 << EOF
1 A hoge
1 B fuga
2 A piyo
2 B pohe
3 A fugaa
EOF
* A B
1 hoge fuga
2 piyo pohe
3 fugaa なし

インデックスが複数フィールド存在するとき

縦のインデックスが複数フィールド存在するときはnumの値を変更します。

In [6]:
map num=2  << EOF
1年 1組 A hoge
1年 1組 B fuga
1年 2組 A piyo
1年 2組 B pohe
EOF
* * A B
1年 1組 hoge fuga
1年 2組 piyo pohe

横のインデックスが複数フィールド存在するときは以下の様です。

In [7]:
map num=1x2  << EOF
1年 1組 A hoge
1年 1組 B fuga
1年 2組 A piyo
1年 2組 B pohe
EOF
* 1組 1組 2組 2組
* A B A B
1年 hoge fuga piyo pohe

データが複数フィールド存在するとき

データが複数存在するときは新たにA,Bとラベル付けして縦の列に追加してくれます。

In [8]:
map num=1 << EOF
1年 1組 hoge hogee
1年 2組 fuga fugaa
2年 1組 piyo poyoo
2年 2組 pohe pohee
EOF
* * 1組 2組
1年 A hoge fuga
1年 B hogee fugaa
2年 A piyo pohe
2年 B poyoo pohee

ラテン文字ではなく、数値でラベル付けをして欲しいときは-nオプションを使います。

In [9]:
map -n num=1 << EOF
1年 1組 hoge hogee
1年 2組 fuga fugaa
2年 1組 piyo poyoo
2年 2組 pohe pohee
EOF
* * 1組 2組
1年 1 hoge fuga
1年 2 hogee fugaa
2年 1 piyo pohe
2年 2 poyoo pohee

横のデータを横方向に展開させたいときは+yarr を付けます。

In [10]:
map +yarr num=1  << EOF
1年 1組 hoge hogee
1年 2組 fuga fugaa
2年 1組 piyo poyoo
2年 2組 pohe pohee
EOF
* 1組 1組 2組 2組
* a b a b
1年 hoge hogee fuga fugaa
2年 piyo poyoo pohe pohee

+yarrを付けた場合も-nで数値でラベル付けることができます。

In [11]:
map +yarr -n num=1  << EOF
1年 1組 hoge hogee
1年 2組 fuga fugaa
2年 1組 piyo poyoo
2年 2組 pohe pohee
EOF
* 1組 1組 2組 2組
* 1 2 1 2
1年 hoge hogee fuga fugaa
2年 piyo poyoo pohe pohee

同様a,bのラベル付けが不要なときは+arrを付けます。

In [12]:
map +arr num=1  << EOF
1年 1組 hoge hogee
1年 2組 fuga fugaa
2年 1組 piyo poyoo
2年 2組 pohe pohee
EOF
* 1組 1組 2組 2組
1年 hoge hogee fuga fugaa
2年 piyo poyoo pohe pohee

一行のデータを複数に区切る方法

-<数値>オプションを使うことで、データをよしなに区切ることもできます。

In [13]:
map -3 num=1 << EOF
X x 1 2 3 4 5 6
X y 7 8 9 A B C
Y x D E F G H I
Y y J K L M N O
EOF
* * x x y y
* * a b a b
X A 1 4 7 A
X B 2 5 8 B
X C 3 6 9 C
Y A D G J M
Y B E H K N
Y C F I L O

但し欠損データの補完はできない様です。

In [14]:
map -3 num=1 << EOF
X x 1 2 3 4 5 6
X y 1 2 3 4 5
Y x 1 2 3 4 5 6
Y y 1 2 3 4 5 6
EOF
Error[map] : フィールドが足りません。

結論

Tukubaiは便利

2018年1月2日火曜日

Synergyを使った似非デュアルディスプレイ

明けましておめでとうございます。年末年始ということで家で大掃除及び諸々の作業をしていました。家の環境ですが、デスクトップのArch Linuxにディスプレイを二枚繋いでデュアルディスプレイの環境でした。が、大掃除をしたところ片側のディスプレイ (ちなみにNexDockです)の電源周りが死んでしまい新年早々仕事をする気が失せたのでその辺の話を書きます。

速い話Synergyを使ってデュアルディスプレイの様なことをやりました。普通に新しいディスプレイを買えば良い話ではあるのですが、それまでの繋ぎという感じです。今回は丁度手元にあったMacBook Proを使います。MacBook Proを手元のディスプレイに指せば良いと思うかもしれませんが、変換コネクタが手元にないので今はできません。

Synergy

さて、こういう話は例によってArch Wikiに書いてあります。(Extreme Multihead) どうも選択肢はXdmxとSynergyがあるようです。

Xdmx a proxy server for X allows the X server on remote systems to contribute its monitor to the desktop of a master system. In this case the destop is genuinely extending onto remote systems; windows can be dragged across system boundaries and applications launched from a remote monitor run on the local, master system. In this environment, the remote systems need only provide sufficient resources to run an X session.

Xdmxを使うとXの転送機能を使って結構ちゃんとデュアルディスプレイのようなことができる様です。一方でMacのXでちゃんと動かないのか巷の情報が古いせいなのか動きませんでした。もうちょっと粘ると動くのかもしれません。

synergy this tool allows your keyboard and mouse to access remote systems by making your desktop seem to extend onto the remote desktop. Simply by moving your mouse off the edge of your desktop it will appear on a remote system where both mouse and keyboard can interact with the remote systems GUI (i.e. synergy can connect Macs and Windows systems too). Windows cannot be dragged across system boundaries and indeed applications launched through a remote systems GUI, run on the remote system. For an integrated Linux desktop, disk shares also need to be set-up

Synergyを使うとリモートにキーボードとマウスを送れます。これだけ見るとデュアルディスプレイというよりKVM感がありますが、操作するマシンを切り替える方法が、マウスポインタをディスプレイの外に動かすだけなのでデュアルディスプレイの様な操作ができます。

Installation

Arch Wikiに色々書いてあるのですがやったことはこういう感じです。

Arch Linux (Host) 側

SynergyはArch Linuxではpacmanでインストールできます。GUIを起動すると課金しないと動かない機能があると言われますが、欲しい機能は課金しなくても動きます。

pacman -S synergy
sudo cp /etc/synergy.conf.example /etc/synergy.conf
vim /etc/synergy.conf # 適当に設定を書く
synergys

MacOSX (Guest) 側

SynergyはMacではhomebrewのcaskでインストールできます。GUIで起動すると課金しろと言われますが、必要なのはsynergy-coreだけなのでこれで動きます。

brew cask install synergy
/Applications/Synergy.app/Contents/Resource/synergy-core --client <Hostのアドレス>

2018/09/15更新

Macでのpathが変わっていたので修正しました。

各アプリケーションの使用感

Emacsで諸々を書く

Emacsの場合trampを使うとsshなど経由で外部のファイルを編集できます。例えばLaTeXを書くときに片側でファイルを編集して、コンパイルとプレビューを反対側でやるようなことができます。

Google Chrome

Chromeだと履歴が共有されるのでその辺を上手いことやると動きます。

Xを使うアプリケーション全般

そもそもsshのX転送を使うことでリモートからGUIのプログラムも起動できます。

2017年7月18日火曜日

Git Date Expansion

Webページの最終更新日時を手動で更新するのはやや面倒だしたまに忘れることがあるので自動化したいです。Gitで管理している場合であればattributeを使って自動で更新されるように設定することができます。Gitのattributeについては説明を省くので適宜 Pro Git book 等を参照してください。

さて、今回の要件は次のようになります。

  • Webページ中にLast modified 2017-01-23のような行を保持したい
  • そのような行は最後に更新したときの日時(更新時のdate +%F で得られる値)になるようにしたい
    • amendなどを行なうとGitのコミットに書いてある日時とは異なる点に注意
  • 最終更新日時の情報はcommitされて欲しいがworking treeでは更新されない

まず、htmlファイルに対して"dater"というfilterが適用されるように、.gitattributesに次の内容を書きます。

*.html filter=dater

次にメインの処理内容を書きます。以下の内容を.git/configに追記すれば良いです。working treeからstageされる際にcleanが適用されるので$Last modified$Last modified: $(date +%F)に更新されます。逆にstageの内容をworking treeに戻す際にLast modified:から始まる行を$Last modified$に置換します。これによってworking treeでは最終更新日時の情報は更新されないようになります。

[filter "dater"]
        clean = sed 's/\\$Last modified\\$/Last modified: '$(date +%F)'/'
        smudge = sed 's/\\(Last modified\\):[^<]*/$&$/'

最後に最終更新日時を記述したいファイルに$Last modified$という行を追加することで目標が達成できます。

2016年12月19日月曜日

最近見た不思議なシェルスクリプトを直してみた

この記事は Shell Script Advent Calendar 2016 19日目の記事です。
18日目の記事はryuichiuedaさんの SHELQ: 怪しいシェル芸キュレーションサイト でした。

他の様々なプログラミング言語において良い書き方と悪い書き方があるように、シェルスクリプトにも良い書き方と悪い書き方があります。しかし特にシェルスクリプトの場合は不慣れな人がかなり悪い書き方をしている様です。そこで、幾つかの例を見ながら良い書き方と悪い書き方を比べてみます。

ディレクトリについて再帰的に処理をする

悪い例

$ ls -R | awk '{がんばる}' | 処理

"ls -R" を使うと再帰的にファイルをリストアップすることができます。ということはこの情報を使えば階層の深いファイルについても処理をすることができますね。やった!

良い例

$ find . -print0 | xargs -0 処理 find . -exec 処理 + (あるいは\;)

良く考えてみて下さい。ただ再帰的に処理をするためだけにわざわざ気合を入れてawkでパースする必要があるなら誰かが便利な道具を作っているはずです。こういう場合はfindを使います。findを使えばファイル名や種類、更新日時など様々な条件でファイルを列挙することができます。ただし、xargsに渡す際に空白入りファイル名があると変な場所で区切れるので所定のオプションを付けてヌル文字区切りにすると良いです。

特定のコマンドを実行しているプロセスを列挙する

悪い例

\$ ps ax | grep 実行ファイル名 | grep -v grep | awk '\$0=\$1'
\$ ps ax | grep [実]行ファイル名 | awk '\$0=\$1'

多分何も知らないと最初に挙げている、ps axの結果を実行ファイル名でgrepしてからgrepを弾くようになると思います。しかし実は、一文字に[]を付けても正規表現として内容が変わらないことを利用して自分自身を弾くこともできます。

良い例

$ pgrep 実行ファイル名

プロセス番号以外も取得したいのであれば二つめに挙げた方法を使うのが良いと思いますが、欲しいのがプロセス番号であればpgrepという正にこのために使うものがあります。 (実は少し結果が変わる場合もありますが多分pgrepの挙動が好ましい場合がほとんどだと思います。) さらにプロセスをkillしたいのであればpkillもあるので便利です。環境によっては無いかもしれません。今時のLinux以外の環境のことは知りません。

番外編 (timeout)

ところで僕がこの処理を見たスクリプトは定期的に走らせて前回と同じプロセスが走りっぱなしであれば強制終了するというものでした。これでもいいんですが、単にタイムアウトの処理をやれば済むのであればGNU coreutilsにはtimeoutが入っています。簡単ですね。

時系列ファイル名の最新版取得

ファイル名が「%y%m%d%H%M%S.log」とかで時系列につけられているファイル群のうち、一番新しいのを取得する方法です。ログとか取ってると良くありますね。

悪い例

$ exprを使ってがんばる

もうどうやるのか知りたくもない感じです。80行かけると書けるらしいです。ソートでも実装するんでしょうか。

良い例

$ sort -nr | head -n 1

ソートするだけです。日時は単に数値としてソートしても結果は同じですよね。GNU sortは優秀で、バージョンなど色々な方法でソートできるらしいです。実は数値と辞書順しか使ったことはないですが。

20日目はkunst1080さんの記事です。

2016年5月27日金曜日

第22回ゴールデンウィークの存在疑惑シェル芸勉強会 第1問

相変わらずシェル芸勉強会には参加できなかったので後日解いてみました。とりあえず第一問です。問題と解答はここにあります。

第1問

最初の解答

だいぶ狂った解答です。最初に全体の行数をwcで数えてそこからAWKでこねこねしてます。

場合分けのない解法

ここ
データ数が偶数と奇数の時で場合分けが必要で面倒くさいです。(場合分けのない方法絶賛募集中。)
と書いてあったので場合分けをしない解答も考えました。

気分がわかるようにAWKで一気に書かれている部分をほぐして説明します。 入力が

3.4
13
42
-4
-5
の時は sortして
-5
-4
3.4
13
42
反転したものと横に並べて
-5 42
-4 13
3.4 3.4
13 -4
42 -5
差の2乗と平均を出して
2209 18.5
289 4.5
0 3.4
289 4.5
2209 18.5
sortしたときの第二カラムの値が中央値です。
0 3.4
289 4.5
289 4.5
2209 18.5
2209 18.5

反転したものと横に並べる周りが汚い感じになっちゃってます。もう少し何とかならないものでしょうか(tukubaiとか?)

2016年2月21日日曜日

安心してください。AWKですから。【トポロジカルソート篇】

定期的に思うことですが、アルゴリズム力がないので諸々のアルゴリズムの復習をします。 最も書き慣れている言語のうちのひとつで、結構書きやすいと思うのでAWKで書くことにします。(布教の意味も込めて)

今回はトポロジカルソートを書こうと思います。トポロジカルソートと言えばGNU coreutilsでtsortとして実装されていることがシェルっぽい人のなかでは有名だと思います。 そうは言ってもシェルスクリプトの中でどうやったら上手く使えるのかはわかりません。 トポロジカルソートは入力に対して答えが一意に定まらないのでtsortとは結果がかわるかもしれません。

アルゴリズムの説明

細かい説明はWikipediaを参照してください。トポロジカルソートでは入力として有向グラフが与えられます。出力は有向グラフのnodeを、edgeの向きが逆転しないようにした順序になります。トポロジカルソートの解は一般に一意に定まりません。 有向グラフがリソースの依存関係を表わしていると考えるとき、トポロジカルソートの出力は依存関係を満たすようなbuildなどの順序になります。有向グラフがpartial orderを表わしていると考えるとき、total orderに拡張していると見ることもできます。

プログラムの仕様

AWKでは(gawkでは独自拡張で実装されてますが)多次元配列がなく、一次元の連想配列しかありません。 そのためグラフの辺の情報を


edge[source] = target0 target1 target2 ... targetn
のように空白区切りで実装しています。 sourceに向う辺を検索する部分は、各nodeについてsourceに向かう辺があるかどうかを線形に探索しています。 辺を削除した結果どこにも向う辺がないnodeについては、空白のtargetを代入することで実装しています。

入力はtsortとほぼ同じですが、各行ごとにsourceとtargetのnodeを書く必要があります。出力はtsortと同じ仕様です。

2016年1月1日金曜日

魚へんマッチングコーディング書き初め

先日のシェル芸勉強会で魚へんの漢字を探す問題が出題されました。本当はUnicodeで魚へんの漢字が連続して出てくることを利用して解く問題ですが、それだとなんか面白くないので画像マッチングで解くことにしました。

やったこと

やったことは非常にシンプルで、同一のフォントなら文字が変わっても大体魚へんの部分は一致するだろうという雑な推定を使いました。従って"魚"や"鯊"などの部首の区分では魚かもしれないが見た目が違うものについては対応する気がありません。魚の大きさが全く違うようなデータが来ても全然ダメです。

まあ普通にC++とかで実装すればいいんですが、芸がない (シェル芸という意味ではないですよ) のでC++でCLIのツールの様なものを実装してシェルで動かしたことにしました。

作ったもの

https://github.com/MasWag/image_utils にあります。Arch Linuxで動かしました。おまけで画面をキャプチャするツールも作りました。これはX11じゃないと動かないのでLinuxじゃないと動かないかもしれません。画面をキャプチャしてパターンとマッチした部分をクリックみたいなものを書けて便利です。

動かしかた

画像データは http://www.unicode.org/ から持ってきました。大量に持ってくると怒られそうなのでほどほどにしてください。ローカルに置くと良いと思います。OpenCVではgifは扱えないのでImageMagickなどで事前にpngに変換して下さい。魚へんの部分もImageMagickでcropとかして適当に作ってください。

./imread tachiuo.png gomi.png maguro.png | ./matchTemplate sakanahen.png

を実行すると

0.868365 6 23 0.473221 16 23 0.682904 6 23

みたいな出力がされます。第一フィールドが大きい方が正解っぽいデータです。第二、第三フィールドがマッチした部分の中央の座標です。第一フィールドを見てもわかりますが、今回は6が左側の中心なのでへんらしい場所にマッチしていることがわかります。多分Unicode全部の画像を持ってきてある程度以上マッチしたデータを全部集めると魚へんが残りますが、流石にそんなことはやってません。