dir でワイルドカードを使うと意図しないファイルがマッチする

dir コマンドの出力を使ったバッチファイルを作っていたところ、意図しないファイルが出力されていることに気づいた。「.csv」で終わるファイルのみを出力してほしいのだが、「.csv_header」で終わるファイルも出力されている。

> dir /b *.csv
1190.csv
1190.csv_header
shisetsu_toilet.csv
shisetsu_toilet.csv_header

原因は MS-DOS や初期の Windows で使われていた 8.3 形式のファイル名にあった。ためしに 8.3 形式のファイル名も出力する「/x」オプションをつけて実行してみると、「.csv_header」というファイルが「...~1.csv」のように表現されていた。

> dir /x
…
2019/04/02  10:12             5,424              1190.csv
2019/04/02  10:35               939 1190~1.csv   1190.csv_header
2019/04/02  10:12         1,403,278 shiset~1.csv shisetsu_toilet.csv
2019/04/02  10:36               371 shiset~2.csv shisetsu_toilet.csv_header
…

dir コマンドではワイルドカードはこの 8.3 形式のファイル名にもマッチする。

解決方法 1 ― PowerShell を使う

Windows 7 からコマンドプロンプトに代わる新しいコマンドラインツールとして搭載された Windows PowerShell ではこの問題は発生しない。ただし別のプロセスからコマンドラインプログラムを呼び出すときはコマンドプロンプトが使用されてしまうため、この問題に対処できない。

解決方法 2 ― 8.3 形式のファイル名を生成しないようにする

コマンド側で 8.3 形式のファイル名にマッチさせない方法がないようなので、そもそも 8.3 形式のファイル名を生成させないことにした。

コマンドプロンプトまたは PowerShell を管理者として実行し、次のコマンドを実行する。

> fsutil 8dot3name set c: 1
8dot3name の生成が C: で無効になりました

8.3 形式のファイル名を削除する

設定はすぐに反映されるが、すでに生成された 8.3 形式のファイル名は削除されない。

コマンドプロンプトまたは PowerShell を管理者として実行し、次のコマンドを実行することで、カレントディレクトリ以下にあるファイルやフォルダの 8.3 形式ファイル名を削除できる。

> fsutil 8dot3name strip /v /s .


Twitter bot 鸚鵡ちゃんを Raspberry Pi 3 で動かす

鸚鵡ちゃんは2012年に Twitter 向けに書かれた bot で、タイムラインやリプライから言葉を覚え、覚えた言葉をたまにつぶやいたりリプライに反応したりする。最新の Twitter API に対応するため最近書き換えた。

今まで実験のため PC の電源を入れているときに気分で動かしていたが、たまに動かすと割と反応をもらえることもあり、継続的に動いてもらうべく常時電源の入っている環境で動かすことにした。

Heroku で動いてもらうことも考えたが、主に Web アプリケーションのためのサービスより手元の環境でゴリゴリやったほうが早いだろうと思ってたまたま持っている Raspberry Pi 3 で動かすことにする。Raspberry Pi 3 は無線LAN設定済み。

rbenv のインストール

とにもかくにも apt-get で入る Ruby が古いので rbenv で新しい Ruby を入れるところから始めよう。rbenv の README に従ってインストールするとすんなり入る。

$ git clone https://github.com/rbenv/rbenv.git ~/.rbenv
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
$ echo 'eval "$(rbenv init -)"' >> ~/.bashrc
$ ~/.rbenv/bin/rbenv init

# csh や zsh における rehash と同義
$ hash -r

ここで bash を再起動しないと rehash がうまくいかなかった。

ruby-build を入れる

これは rbenv install するために必要。

$ mkdir -p "$(rbenv root)"/plugins
$ git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build

Ruby 2.5.3 のインストール

最新の安定板は 2.6.1 だが、後述の Bundler に不具合があるそうなので一つ前の 2.5.3 を入れる。インストールには20分程度かかった。

# Ruby のビルドに必要
$ sudo apt-get install ruby-dev

# このライブラリも必要だった
$ sudo apt-get install libssl-dev libreadline-dev libsqlite3-dev

$ rbenv install 2.5.3

Bundler の使用

Bundler は npm のように gem パッケージをローカルにインストールするためのパッケージ。鸚鵡ちゃんを今どきの、プロジェクトごとにパッケージを入れる形にして他の人にも使いやすくする。

Gem を使ってインストールする。

$ rbenv exec gem install bundler
$ rbenv rehash

プロジェクトで使うには、そのディレクトリへ移動し次のコマンドを実行する。

$ cd ~/2236om
$ rbenv exec bundle init

するとそのディレクトリに Gemfile というファイルができるので、インストールしたいパッケージを記述していく。

gem 'pit', '0.0.7'
gem 'twitter', '6.2.0'
gem 'sqlite3', '1.4.0'

Gemfile が用意できたら Bundler を使って実際にインストールする。

$ rbenv exec bundle install --path=vendor/bundle

プログラムからは次のように通常の require の前に bundler を追加する。

require 'bundler/setup'

Cron の設定

鸚鵡ちゃんを cron で動かすため which コマンドで ruby の場所を調べて次のような crontab を書いたがうまくいかない。

MAILTO=""
* * * * * /home/pi/.rbenv/shims/ruby /home/pi/2236om/scheduled.rb

次のように cron のログを出力できるようにして調べて見る。

# cron の行のコメントを外す
$ sudo vi /etc/rsyslog.conf
$ sudo /etc/init.d/rsyslog restart

# すべてのログを出力するようにする: EXTRA_OPTS="-L 15"
$ sudo vi /etc/default/cron
$ sudo /etc/init.d/cron restart

# ログを監視
$ tail -f /var/log/cron.log

ログを見ると Ruby 自体は動くようだが、次のようなログが出力され鸚鵡ちゃんだけ動かない。

Mar 10 11:52:02 raspberrypi CRON[8105]: (CRON) error (grandchild #8109 failed with exit status 1)

どうやら実行ディレクトリが怪しいのでホームディレクトリに移動して鸚鵡ちゃんを起動してみる。

$ cd ~
$ ruby 2236om/scheduled.rb
Traceback (most recent call last):
	2: from 2236om/scheduled.rb:16:in `<main>'
	1: from /home/pi/.rbenv/versions/2.5.3/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'
/home/pi/.rbenv/versions/2.5.3/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require': cannot load such file -- twitter (LoadError)

ということで実行ディレクトリに原因があるので次のように crontab を書き直す。

MAILTO=""
* * * * * cd /home/pi/2236om; /home/pi/.rbenv/shims/ruby scheduled.rb

これでめでたく鸚鵡ちゃんを動かすことができた。

おまけ:apt-get チートシート

やりたいこと コマンド
パッケージリストの更新 sudo apt update
インストール済みは? sudo dpkg -l
パッケージを検索(完全一致) sudo apt list
パッケージを検索(部分一致) sudo apt search
パッケージをインストール/更新 sudo apt install パッケージ名
パッケージを全て更新 sudo apt upgrade

おまけ:鸚鵡ちゃんが利用している Twitter API のレート制限

API Requests/Window Window
GET statuses/home_timeline 15 15 分
GET statuses/mentions_timeline 75 15 分
POST statuses/update 300 3 時間

タブでもスペースでもインデント幅を自分好みに固定できる Atom パッケージ

どんなコーディングスタイルでもインデント幅を自分好みに固定できる Atom パッケージ fixed-indentation-width を公開した。Atom からインストールできる。

ファイルが 2 spaces だろうが 4 spaces, 5spaces それからハードタブ、どんなスタイルでも自分の決めたインデント幅にできる。

使用するにあたっては Atom がそのコードのインデント幅を知っている必要がある。具体的には EditorConfig などを使って、コードのインデント幅とエディタが想定しているインデント幅を揃えておく必要がある。

リポジトリはこちら。

経緯

どこの誰が広めたのか知らないが、「環境によって見え方が変わるから」「patch でハードタブを扱えないから」「ターミナルからコピペするとタブ文字がスペースになってしまうから」などという的外れな理由で、 Web 業界ではインデントにスペース2つが当たり前になっている。

環境によって見え方が変わるのは、フォントによってスペースの幅が違うからスペースだって同じだし、いまどきの patch はタブをちゃんと扱えるし、そもそもターミナルからコピペすんなよと言いたいところだが、今は prettier だって使えるし問題ない。

現時点での最大の問題は、指定数のスペースしか許さんとぬかしている輩のせいで、ユーザがそれぞれ見やすいインデント幅に設定できないことだ。特にプロポーショナルフォントで表示するとスペース2つなんて漢字一文字よりも狭いからインデントしているんだかしていないんだかはっきりしてほしい状態になる。

しかもだ、一般人が GoogleAirbnb の使っているコーディングスタイルがクールだと言って真似する。そうすると自力で prettier をセットアップできない一般人は悲しいことに、スペースを1つだけ削ったり余計に足したりしてインデントをガタガタに崩してしまう。

一方タブでインデントを行えば、現在使われているほとんど全てのエディタはタブの幅を設定する機能があるので、ファイルのバイト列は変えずに各個好みのインデント幅に設定できる。スペースと違って目立つので一般人にも優しい。

とはいうものの宗教だとか政治の世界になってしまうので、何とか解決するものはないかと Atom をいじくり回してできたのがこのパッケージ。

既知の問題

  • 2段以上のインデントの中間にカーソルを移動させるとカーソルが見えなくなる
  • 起動直後はインデント幅がちゃんと設定されない(内容を変更すると直る)

解決手段を思いついた方は教えてください。

TinyMCE でペースト時に不要なスタイルを削除する

TinyMCE | Content Filtering によると、TinyMCE を初期化する際に valid_styles または invalid_styles オプションを指定することで、不要なスタイルを削除できると書かれている。

tinymce.init({
	selector: 'textarea',  // change this value according to your HTML
	valid_styles: {
		'*': 'border,font-size',
		'div': 'width,height'
	}
});

しかしながらこの機能、エディタの初期化にしか効かないようで、Web ページや文書作成アプリケーションから貼り付けたときには不要なスタイルがついたままになってしまう。

これを解決するには TinyMCE の API を使用して

  1. ペーストイベントを補足
  2. コンテンツを走査
  3. それぞれの要素に対して不要なスタイルを除去

という手順が必要になる。

具体的には初期化時に setup オプションを指定し、エディタごとにこの処理を登録してやればよい。

tinymce.init({
	selector: 'textarea',  // change this value according to your HTML
	valid_styles: {
		'*': 'border,font-size',
		'div': 'width,height'
	},
	setup: function(editor) {
		editor.on("paste", function(e) {
			// ペースト後に実行
			setTimeout(function() {
				// Styles クラスの機能に不要スタイルの除去がある
				var Styles = new tinymce.html.Styles({}, editor.schema);

				// TreeWalker を使用してすべての要素に対して操作を行う
				var walker = new tinymce.dom.TreeWalker(editor.getBody());
				do {
					var el = walker.current();
					if (!el.getAttribute) {
						continue;
					}
					// 各要素の style 属性を Styles クラスで解析すると
					// valid_styles, invalid_styles が適用されるので、
					// それをふたたび style 属性に書き込む
					var styleString = el.getAttribute("style");
					if (!styleString) {
						continue;
					}
					var s = Styles.parse(styleString);
					el.setAttribute("style", Styles.serialize(s, el.nodeName));
				} while (walker.next());
			});
		});
	},
});

iiiiiiii.com ooooiiii.com dabadabadab.com lalalaa.com で流れている音楽の元ネタ

iiiiiiii

www.youtube.com
חוה אלברשטיין (Chava Alberstein) という歌手の בלדה על סוס עם כתם על המצח (額に斑のある馬のバラード) という曲

ooooiiii

www.youtube.com
イスラエルの טיפקס (Teapacks) というバンドの הרבי ג'ו כפרה (Harabi Joe Capara) という曲

Daba Daba Dab

www.youtube.com
イスラエルのソングライター Jonathan Geffen の Small Talk という曲。dabadabadab.com は現在ドメインの有効期限が切れている

Lalalaa

調べきれず