git で特定のファイルだけ取ってくる(自分用メモ)

git checkout fname

commit 前のファイルを git stash で上書きしてしまった!どうする?(自分用メモ)

要約
git stash pop が使えないか検討しよう.

背景
共同作業しているプロジェクトで,「どれどれ,最近の他の人の作業どうなってるかな」という軽い気持ちで git pull したあなたは pull が失敗することに気づいた.「よくわかんねえな」と呟いたあなたはさらに何気なくgit stash してしまう.とりあえずチームの作業を確認したあなたは,作業中だったエディタに向かった.そして異変に気づく:「あれ…このファイル,前回の commit の状態に戻されてるぞ.」そう,あなたが前回の commit から数日間の間に行った大量の変更は消し去られ,数日前の状態に戻ってしまったのだ.

対処
“stash”というのは,何かをこっそり隠すだとか取り除けておく,というような意味合いの言葉です.
その名前が示唆するように,git stash したとき,先程まで保存されていたファイルは(保存されていなかったとしたら流石にアウトだと思うので,エディタが自動的に保存しているバックアップなどを探すしかないでしょう)どこかに置かれています.

最後の stash で退避したファイルを戻すには git stash pop すれば良いようです.

習慣による回避
このような回復手段が git に備わっていることは大変素晴らしいことですが,驚いたり焦ったりすると利用可能な思考のリソースが削がれてもったいないので,日頃から些細な変更のあとにも躊躇なく commit するといいんだろうな~.

時間があるときに調べて書き足すこと
git stash list とかしたときに幾つか stash の結果が出てくるけど,0が一番新しいやつなのか?とかよくわからなかった.stash を複数回やってしまった場合などに回復するためには stash list で得られたリストの時系列をちゃんと知っておくべき.

atom で non-greedy な正規表現を使う(自分用メモ)

■短い答え: ?をうまく使え。
古い論文をOCRで処理している。するとOCRのミスで
“apple’
というようなものが出てきた。これが意図通りなら問題ないが本来は
“apple”
となって欲しい。こういう例が随所にあるので一括して処理するために正規表現を使おうと思った。

■最初に
"(.+)'
を試したが、正規表現がgreedy、つまり、この表現にマッチする最大長の文字列を探してしまうため、得られたテキストデータが「一段落につき改行一つ」だったりすると大変困る。そこで、non-greedy なマッチをさせる ? をつかって
"([^"]+?)'
のようにした。ここで[^"]を使っているのは
“I have a pen,” he said. Soon after that, he stook the pen to the apple, and said “apple-pen’.
みたいな文章が全文選択されるのを防ぎたいから。

■non-greedy なオプションは他の正規表現エンジンでも使えることが増えてきてる気がするけど、atom 以外でどうなってるかは知らない。

VMware Tools の手動アップグレード(自分用メモ)

ヘルプページには初回用の操作も書いてあって説明が分岐して読むのが疲れるので、手動アップグレードの手続きを自分用にメモしておく。

$ sudo su
[sudo] uname のパスワード:
# mount /dev/cdrom /mnt/cdrom
# cd /tmp
# rm -rf vmware-tools-distrib
# ls /mnt/cdrom

VMwareTools-xxx-yyy.tar.gz が見えてるはず

# tar zxpf /mnt/cdrom/VMwareTools-x.x.x-yyyy.tar.gz
# cd vmware-tools-distrib
# ./vmware-install.pl

質問されたら全部Enterで返事しておく。

msys2 上で ocaml をビルドしようとして失敗した記録

■真新しいmsys2上でomakeを使いたくなったが、周知の通り現在はWindows用のバイナリが配布されていない。
msys2上のocamlでomakeをビルドしようとしたが上手く行かない。そこで、msys2上でocamlをビルドしてみればいいのではないかというアホなことを考えて失敗した記録。

■準備。本当に必要かどうかはわからない。

$ pacman -S gamin #fam みたいなもの
$ pacman -S bison #yacc みたいなもの
$ pacman -S gcc git patch

■ocamlをビルドする

#ocaml を msys2 上でビルドする。
$ git clone https://github.com/ocaml/ocaml
$ cd ocaml
$ ./configure -host x86_64-w64-windows -cc "gcc -Wno-error=implicit-function-declaration -Wno-error=int-conversion -Wl,--stack,16777216"
$ make clean
$ make world
$ make install

ln: シンボリックリンク 'ocamlyacc' の作成に失敗しました: No such file or directory
make: *** [Makefile:606: install] エラー 1

■msys2でsymlinkを使う方法:msys2_shell.cmd をテキストエディタで編集し

rem To activate windows native symlinks uncomment next line
rem set MSYS=winsymlinks:nativestrict

となっているところを

rem To activate windows native symlinks uncomment next line
set MSYS=winsymlinks:nativestrict

に変更して保存する。そして、msys2_shell.cmd を右クリックして「管理者として実行」してmsys2のシェルを立ち上げる。

■手持ちの別のマシンでやったところ ocamlyacc のエラーは出なかったが omake のビルドで

$ ocaml configure.ml
Cannot load required shared library dllcamlstr.
Reason: dllcamlstr.so: dynamic loading not supported on this platform.
Cannot load required shared library dllunix.
Reason: dllunix.so: dynamic loading not supported on this platform.
File "./configure.ml", line 1:
Error: Reference to undefined global `Str'

となって止まってしまった。

Haskell の QuickCheck を自動化する

ライブラリを開発していると、複数のテストを一挙に回したくなるかもしれませんね。そんなときはこうします。

{-# LANGUAGE TemplateHaskell #-}

import Data.List
import Test.QuickCheck

-- 与えられた2つのリストを連結する
cat :: (Eq a) => [a] -> [a] -> [a]
cat [] ys = ys
cat (x:xs) ys = x : (xs `cat` ys)

-- cat が結合律を満たすかどうかのテスト
prop_cat xs ys zs = (xs `cat` ys) `cat` zs == xs `cat` (ys `cat` zs)

-- 最初のリストから二番目のリストの要素を除去したリストを作る
sub :: (Eq a) => [a] -> [a] -> [a]
sub [] ys = []
sub (x:xs) ys | x `elem` ys = xs `sub` ys
| otherwise = x : (xs `sub` ys)

-- sub が結合律を満たすかどうかのテスト
prop_sub xs ys zs = (xs `sub` ys) `sub` zs == xs `sub` (ys `sub` zs)
--to run this test, > quickCheck prop_cap

--最初のリストに含まれている要素を除外しつつ2つの与えられたリストをマージする
ucat :: (Eq a) => [a] -> [a] -> [a]
ucat [] ys = ys
ucat (x:xs) ys | x `elem` ys = x : (xs `ucat` (ys `sub` [x]))
| otherwise = x : (xs `ucat` ys)

-- ucat が結合律を満たすかどうかのテスト
prop_ucat xs ys zs = (xs `ucat` ys) `ucat` zs == xs `ucat` (ys `ucat` zs)

return []
main = $forAllProperties (quickCheckWithResult stdArgs { maxSuccess = 2000 })

■動かし方/その出力例

$ stack runghc qc.hs
Run from outside a project, using implicit global project config
=== prop_cat from qc.hs:12 ===
+++ OK, passed 2000 tests.

=== prop_sub from qc.hs:20 ===
*** Failed! Falsifiable (after 9 tests and 7 shrinks):
[0]
[]
[0]

=== prop_ucat from qc.hs:29 ===
+++ OK, passed 2000 tests.

■コードの解説
cat, sub, ucat というリスト演算を定義し、それらが結合法則を満たすかどうかチェックしています。テストの結果、cat は合格、subは失格(つまり結合法則の反例が見つかった)、ucatは合格となりました。

■ポイント
1. TemplateHaskell を使う。
2. テストの名前は prop_ で始まる。 (TemplateHaskellを使っていることからの制約)
3. return[] とかいうキモいやつは我慢。 (TemplateHaskellを使っていることからの制約)
4. main は一番最後に来る。 (TemplateHaskellを使っていることからの制約)

Makefile自己文書化の仕組み(メモ)

Makefileを自己文書化するという翻訳記事を見つけた.

Makefileをこんな風に作ったとする:

help:
	@grep -E '^[0-9a-zA-Z_-]+[[:blank:]]*:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[1;32m%-30s\033[0m %s\n", $$1, $$2}'

foo : bar.cc baz.cc  ## compiles foo

bar : aaa.cc bbb.cc ddd.cc

baz : hoge.h poyo.cc  ## makes baz

$ make すると help が実行されて

baz                            makes baz
foo                            compiles foo

のように出力される.この help ターゲットに書かれてるワンライナーがこの仕事を引き受けてくれている.(なお,オリジナルのワンライナーを少し改造してある).あとで挙動を変えてみたくなるかもしれないので,このスクリプトが何をやっているのか調べてみた.

tricks in the 'self documented makefile'

Makefile自己文書化の鍵となるワンライナー

[[:blank:]]
オリジナルのワンライナーから変えたところの一つです.私は行儀が悪いので make のターゲットを
targetname: hogehoge
ではなく
targetname : hogehoge
のようにターゲット名の後ろにも空白を置く癖があります.grep で空白にマッチする正規表現は[:blank:]なので,任意個の空白は空白の文字クラス[[:blank:]]によって[[:blank:]]*と表されるわけです.

Field Separator
FS = ":.*?##" のようにフィールドセパレータが定義されている.これにより## に引き続いてコメントが置かれたMakefileのターゲットの行が,ターゲット名($1)とコメント部分($2)に分かれてくれます.

$(MAKEFILE_LIST)
makefile の名称を取り出します.言っていることがわかりにくいですか? ではこうしましょう.
OtherMakefile という名前のファイル

.PHONY : a
a :
    @echo "this file is: $(MAKEFILE_LIST)"

として作り,ファイル名指定オプション -f を使って make を呼びます:
$ make -f OtherMakefile
すると
this file is: OtherMakefile
と返ってくるはずです.

カラーコード
\033m[0m で色の設定が解除されています.次のMakefileで色々試せます:

attribute :
	@awk 'BEGIN{printf "\033[1;32mhello\033[0m\n"}'
	@awk 'BEGIN{printf "\033[2;32mhello\033[0m\n"}'
	@awk 'BEGIN{printf "\033[3;32mhello\033[0m\n"}'
	@awk 'BEGIN{printf "\033[4;32mhello\033[0m\n"}'
	@awk 'BEGIN{printf "\033[5;32mhello\033[0m\n"}'
	@awk 'BEGIN{printf "\033[7;32mhello\033[0m\n"}'

foreground :
	@awk 'BEGIN{printf "39:Default foreground color [\033[1;39mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "30:Black [\033[1;30mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "31:Red [\033[1;31mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "32:Green [\033[1;32mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "33:Yellow [\033[1;33mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "34:Blue [\033[1;34mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "35:Magenta [\033[1;35mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "36:Cyan [\033[1;36mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "37:Light Gray [\033[1;37mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "90:Dark Gray [\033[1;90mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "91:Light Red [\033[1;91mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "92:Light Green [\033[1;92mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "93:Light Yellow [\033[1;93mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "94:Light Blue [\033[1;94mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "95:Light Magenta [\033[1;95mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "96:Light Cyan [\033[1;96mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "97:White [\033[1;97mHere\033[0m]\n"}'

background:
	@awk 'BEGIN{printf "49:Default background color [\033[0;49mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "40:bg:Black [\033[0;40mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "41:bg:Red [\033[0;41mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "42:bg:Green [\033[0;42mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "43:bg:Yellow [\033[0;43mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "44:bg:Blue [\033[0;44mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "45:bg:Magenta [\033[0;45mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "46:bg:Cyan [\033[0;46mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "47:bg:Light gray [\033[0;47mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "100:bg:Dark gray [\033[0;100mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "101:bg:Light red [\033[0;101mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "102:bg:Light green [\033[0;102mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "103:bg:Light yellow [\033[0;103mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "104:bg:Light blue [\033[0;104mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "105:bg:Light magenta [\033[0;105mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "106:bg:Light cyan [\033[0;106mHere\033[0m]\n"}'
	@awk 'BEGIN{printf "107:bg:White [\033[0;107mHere\033[0m]\n"}'

Makefile で basename や strip を使う(自分用メモ)

こんな Makefile があったとします:

.PHONY : aaa

aaa : bbb.hs   
    ghc  bbb.hs
    ./bbb

Makefile に少し慣れてくると,$< を使って

.PHONY : aaa

aaa : bbb.hs   
    ghc  $<
    ./bbb

のように書くかもしれませんが,今度は ./bbb の箇所が気になります.しかし,コマンド basename を使って

### DOES NOT WORK
.PHONY : aaa

aaa : bbb.hs   
    ghc  $<
    ./$(basename .hs $<)

としてやってもうまくいきません.先頭に空白が残るからです.そこで Make のコマンド strip を使って

aaa : bbb.hs
    ghc $<
    ./$(strip $(basename .hs $<))

としてやると,期待した通りの動作になります.

atan2の引数順序をすぐ思い出すための恒等式

二次元直交座標系から極座標系に変換する際に、あるいは「ほとんど同じ話」ですが{x+iy} という形式の複素数を極形式に変換する際に二つの与えられた実数からある角度を得たい場合があります。そのような場合に便利なのが atan2 であることはご存知と思います。私はこの関数の引数の順序を数年に一度はネットで調べてる気がします:こういうのは全く無駄な時間です。

そこで、少し落ち着いて考え、次の恒等式を覚えておけばもう迷わなくなりそうだと思ったのでメモしておきます:

{\theta=\mathrm{atan2}(\sin(\theta), \cos(\theta))\quad(\theta \in [0,2\pi)).}

特定のパターンの出現数をカウントをする

テキスト全体で特定の文字やパターンが何回出現するのかコマンドラインから調べたくなりました。

sed でやるのかなと思ったけど grep -o が使えるみたいです。

$ echo "SSwSStSSSSoSS" | grep -o  'S' | wc -l
10

wc -l は与えられたテキストの行数をカウントするコマンドです。

もう少し大きなテキストで試してみましょう。次のような内容の alice.txt があるとします:

Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, `and what is the use of a book,’ thought Alice `without pictures or conversation?’

So she was considering in her own mind (as well as she could, for the hot day made her feel very sleepy and stupid), whether the pleasure of making a daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly a White Rabbit with pink eyes ran close by her.

There was nothing so very remarkable in that; nor did Alice think it so very much out of the way to hear the Rabbit say to itself, `Oh dear! Oh dear! I shall be late!’ (when she thought it over afterwards, it occurred to her that she ought to have wondered at this, but at the time it all seemed quite natural); but when the Rabbit actually took a watch out of its waistcoat-pocket, and looked at it, and then hurried on, Alice started to her feet, for it flashed across her mind that she had never before seen a rabbit with either a waistcoat-pocket, or a watch to take out of it, and burning with curiosity, she ran across the field after it, and fortunately was just in time to see it pop down a large rabbit-hole under the hedge.

In another moment down went Alice after it, never once considering how in the world she was to get out again.

このテキストに nk という並びが何回登場するかコマンドラインから数えてみます:

$ less alice.txt | grep -o 'nk' | wc -l
3