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/MacOS/synergy-core --client <Hostのアドレス>

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

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全部の画像を持ってきてある程度以上マッチしたデータを全部集めると魚へんが残りますが、流石にそんなことはやってません。

2015年12月28日月曜日

第20回シェル芸勉強会でびっくりしたことまとめ

第20回シェル芸勉強会に参加しました。幾つか初めて知って(過去に見たことがあるかもしれないけど)びっくりしたことがあったので備忘録としてまとめてみた。基本的に午前中で燃焼したので午後のことは書いていない。manを読むべきということを再確認した。そもそもGNUの指針だとmanにいっぱい書いてあるのは良くないはずじゃなかったっけ、とか言う話は知らない。(本当はinfoに書くべき(?))

AWKのPattern Ranges

とりあえずman抜粋

A pattern range consists of two expressions separated by a comma; in this case, the action shall be performed for all records between a match of the first expression and the following match of the second expression, inclusive. At this point, the pattern range can be repeated starting at input records subsequent to the end of the matched range.
見たことあるかもしれないけど、知らなかった。というかパターンのとこにカンマをカンマ演算子のつもりで書いてうまくいかなかったことがあったかも。 つまり

awk 'NR==2,NR==4'

sed -ne '2,4 p'
と同じ意味になるらしい。ついでに言うと

awk 'NR==2,0'

sed -ne '2,$ p'
と同じ意味で使うらしい。

nawkとそれ以外の$0代入の挙動が微妙に違う

これはやばいやつ。MacOSXだとawkがnawkらしいので結構重要かも。

具体的には(i > 1)で


awk '$0=$i'
の挙動が怪しい。gawkとmawkでは全体の真偽値が$iの真偽値と一致すると思って良いがnawkではそうでもないらしい。manを読んでもよくわからなかったので適当にコードを実行して調べた。本を読むと良いのかも。少なくとも調べた限りでは$iの中身がstringの場合には思った通りの挙動をするが、numericの場合には常に偽を返すっぽく見える。

もちろん


nawk '$0=$i'

nawk '($0=$i)||($0)'
の結果は変わらないのだが、(numericだと偽)

nawk '($0=$2)||(($1=$1)&&$0)'
ということにして一回フィールドを書き換えると$0の真偽値が想定しているものに変わる。因みに$0の値はprintして見る限りでは特に変なことになっていない。この挙動が意図したものなのかバグなのかはよくわからないが、少なくともMacOSXでドヤ顔して$0への代入をすると冷や汗をかくことになりそう。

seqと{..}

seq 100 1はだめだけどecho {100..1}が動くの知らなかった。{1..10..2}ができることも知らなかった。

因みに{foo,bar}で色々やる話は知っているけど技術的に使えないやつなのでとりあえず置いておく。${foo:ここ色々}系列も見たことあるし使ったこともある(manを見ないと半分くらい使えない)から今回は置いておく。

午後も自分じゃない端末ってどうやって判別するのかとかよくわかっていない点はあった(今もちゃんとやるにはどうすればいいかよくわかっていない)が、サーバエンジニアじゃないしな、って言って忘却の彼方に投げやった。