startコマンドとスペースの相性
昨日のstartコマンドについて、さらに問題が起きたので追記。
というのも、よくある「コマンドとスペースの相性が抜群に悪い」ということです。
ただ、それにしても、startコマンドは非常に奇妙な動きをしたので、まとめ。
当然ながら、以下の呼び出しはエラーになります。
start C:\Program Files\Hoge\Hoge.bat
Program と Filesの間の空白でコマンドが区切られてしまうからです。
では、以下のように変えてみましょう。
start "C:\Program Files\Hoge\Hoge.bat"
空白を含むパスのために、二重引用符で囲みました。一見大丈夫そうです。
しかし、これも実はダメなのです。
startコマンドは、新規で作るコマンドプロンプトのタイトルが設定できます。
それが、""で囲った最初のテキストになるのです。
つまり、上の命令は、肝心のコマンドがタイトルの指定になってしまいます。
ということで、以下になります。
start "Hoge" "C:\Program Files\Hoge\Hoge.bat"
なんでもいいんですが、タイトルを付けます。
すると、二つ目の二重引用符は無事コマンドになるのです。
と、これだけで解決すればよかったのですが……。
実は、さらに問題は隠れています。バッチ処理、引数、渡したい時ありますよね?
その引数に空白があったらどうしましょうか、当然こうするでしょう。
start "Hoge" "C:\Program Files\Hoge\Hoge.bat" "C:\Program Files\Hoge\Foo.txt"
これは、実はエラーになります。
困ったことに、startが「"C:\Program Files\Hoge\Hoge.bat" "C:\Program」をコマンドとして認識してしまうのです。
バグなんじゃないか、、、とすら思うんですが、こういう挙動になってます。
つまり、コマンド・その引数、両方にスペースがある場合、そのままではどうやってもうまく行かないのです。
では、諦めるしか無いのでしょうか?
そんなことはありませんでした。
for %A in (C:\Program Files\Hoge\Hoge.bat) do start "Hoge" %~sA "C:\Program Files\Hoge\Foo.txt"
for構文を使います。
forを使うことで、コマンドを一度引数に取り込み、パス修飾「%~s」でショートネーム(8.3形式)にするのです。
そうすれば、コマンドには空白は含まれない安全なパスになります。
そして、幸運なことにコマンドがちゃんと空白なしで渡せれば、引数は二重引用符で囲っていても問題ありません。
(このあたりの仕様の微妙さは、若干不安が残りますが……)
結果、非常に面倒になりましたが、どのパスに空白があっても、なんとか問題なく実行できるようになりました。
それにしても思うのです。
なんで、こんなに空白に弱いのに、パスに空白を含めることを許可した上、
システムが作るフォルダに空白があるのか(Program Files)。
このあたりは、もうちょっとシステム的にサポートして欲しいと感じるものです。
スレッドとコンソール
よく面倒な繰り返し作業は、perlで書いて自動化しているのですが
このたび、どうしたらいいものか、という問題がひとつ。
お仕事を探して、それらを全部Thread::QueueにEnqueueして
Queueが空っぽになるまで、スレッドでお仕事を行ってもらう。
ただ、それだけのことだったのですが、そのお仕事(バッチ処理)の出力が
全部同じperlを実行したコンソールに出力されてしまうという……。
別に、ただの結果のアウトプットなので混ざってても別にいいのですが
もしできるならば、コンソールを複数出しておきたいなぁ、とか思ったり。
そういうことって、できるのかなぁ、と探してみたけど直ぐには見つからず。
んー、ユニークな名前でファイル作って出力しておくのが妥当かなぁ。
なにかお手軽な方法がないものでしょうか。
新規コンソール
スレッドとコンソールという前回の日記にて、スレッドで複数バッチ処理を起動すると、
コンソールへの出力が混ざってしまって……。
という話をしていましたが、あっさり解決したので、そのことに関して。
単純にコマンド「start」を使う。それだけでした。
startは、新規コンソールにてコマンドを実行するコマンドです。
/wait オプションにて、処理終了まで呼び出し側に処理が戻らないので、それも利用します。
use threads; use Thread::Queue; $thread_queue = Thread::Queue->new(); $thread_queue->enqueue(1); $thread_queue->enqueue(2); $thread_queue->enqueue(3); $thread_queue->enqueue(4); my $thd1 = threads->create(\&proc, "One"); my $thd2 = threads->create(\&proc, "Two"); $thd1->join(); $thd2->join(); sub proc { while(0 < $thread_queue->pending) { if( my $data = $thread_queue->dequeue ) { if( my $pid = fork() ) { threads->yield(); wait(); } else { exec 'start "Title" /wait wait.bat 2'; } } } }
こんな感じで、呼びだすといい感じになってくれました。
コマンドを未だにちゃんと把握しきれていないのは勿体無いな、と思いました。
ちゃんと勉強しないとダメですね。
グラフィカルに
私は、そろそろiPhone4を買おうかと、悩んでいる頃なのですが。
そんな折に、Androidに面白そうなのが登場。
App Inventor
子供向けの教育系でグラフィカルな言語は見たことがあるけど
ちゃんとしたツールやゲームを作れるものとしての言語というのは
見たことが無かっただけに驚きです。
グラフィカルなプログラミング言語というと、
ぱっと「宇宙のステルヴィア」のプログラムが浮かぶ、そんな私。
しかし、チュートリアルを見る限りでは……いくらグラフィカルになっても
当たり前ながらプログラムとしての「構造」は最低限必要なようで。
むしろ、規模が大きくなると、かえって見通しが悪くなるのではないかという懸念が……。
また、末端の修正はいいですが、繋がったピースの真ん中付近を変える時は面倒なのでは?
と感じてしまったりするけど、その辺はどうなんでしょうか。
とはいえ、面白そうなのは間違いないですね。触ってみましょう。
_SECURE_SCLによる差
_SECURE_SCLは、チェック付きイテレータ用の定義シンボルです。
STLのvectorやlistをインクルードする際に
#define _SECURE_SCL 1 // 有効にする //#define _SECURE_SCL 0 // 無効にする #include <vector>
という感じで使います。
チェック付きイテレータとは何か、というのは
以下のMSDNを見て貰えるとよいと思います。
http://msdn.microsoft.com/ja-jp/library/aa985965.aspx
こちらを使っていて、起き得る問題についてのお話を今日は少し。
#include <cstdio> #include <vector> int main(int argc, char* argv[]) { typedef std::vector<int> IDs; printf("_SECURE_SCL = %d\n", _SECURE_SCL); printf("sizeof(IDs) = %d\n", sizeof(IDs)); return 0; }
こちらの、ただのstd::vector
_SECURE_SCLが、有効か無効かで異なる結果になります。
以下が、VisualStudio.net2010(VC10)での結果です。
_SECURE_SCL = 1 sizeof(IDs) = 20
_SECURE_SCL = 0 sizeof(IDs) = 16
と、_SECURE_SCLの設定で異なったサイズを返すのです。
これ単体では、確かにそう問題にはならないのですが、
例えば、スタティックライブラリと、それをリンクしている
メインプログラムで_SECURE_SCLの設定が異なった場合は
クラスサイズに齟齬が出る影響で、アクセス違反などを起こす場合があります。
また、これの厄介なところは、クラスサイズが異なるのは
「Release」のみです(正確には、NDEBUG定義の有無)。
_SECURE_SCL以外にも、定義の有無でサイズが変わるものは
同様の危険があるので、気をつける必要があると思います。