バッチファイルの闇

Windowsコマンド、本当に融通が効かなくてつらい。にわかで操作できるものではないようだ。いろいろメモしておく。

1、変数への代入は基本文字列としてあつかわれる。すべては文字列。set x=3 の場合3は文字列。そして余計なスペースをいれない。これはシェルでもおなじ。

2、数値計算を行いたいときはaオプション。set /a x=3+4 たぶんこれでいい。

3、タスクスケジューラ-からpythonスクリプトを実行するときは、svchost.exeという強そうなコマンドからpython.exeがスポーンされる。

4、バッチファイルを実行するのは、コマンドを順番に実行するのと同じことである。新しいcmdプロセスが生成されたうえでコマンドがスポーンされるわけではなく、既存のcmdプロセスからスポーンされるだけ。(その点Linuxではバッシュファイルを実行すると、新たにbashが起動されてそのうえでコマンドが実行されていく。)

5、start command/batch.bat は、新しくcmd.exeがフォークされてからそこでコマンドが実行される。Linuxでいうところのスポーンに相当する。start /wait の場合は、子プロセスの終了を回収する。大事。start /bはバックグラウンドのbかとおもいきや、親プロセスと同じ端末を共有する。ややこしい。call commandはフォアグラウンドでコマンドが実行される。つまりふつうにcommandを入力するのとおなじ。call batch.bat も新しくcmd.exeがフォークされるわけではない。batch.batを実行するのとおなじ。 しかしブラウザやエディタをコマンドプロンプトからcallで呼び出しても、なぜか制御はうつらない。バックグラウンドで起動されたような感じになる。よくわからない。

6、batchファイルの中のfor文の変数は%%iというふうに%を2つ必要とする。ただのコマンドの場合は%iというふうにひとつでいい。

7、shell script のgrepにあたるコマンドは、findstrという。

8、最後にして最大の関門は遅延変数。いいかげんにしろ。自らのプロセスIDを取得することすら容易ではない。

for /f "usebackq tokens=2 delims=," %%i in (`tasklist /v /fo csv ^| findstr "cmd.exe" ^| findstr "THIS"`) do (
    set thiscmdpid=%%i
    set thiscmdpid=!thiscmdpid:~1,-1!
    echo !thiscmdpid!
)
title THIS
call main

なにかしらのプロセスのIDを外部プロセスから特定したかったのだが、親子関係にない場合どうすればいいのかわからなかった。苦肉の策としてtitle コマンドで名前をつけることにした。上記のバッチファイルを実行すると、現在同じバッチが実行されているプロセスを探知することができる。それにしても遅延変数を知らなかったので、なにか実行するたびに結果が規則的に変わっていくので困った。


qiita.com

最終的にPowershellを使うと解決することが判明した。

stackoverflow.com

これ自分の質問。英語版のstuck overflowは本当にありがたい。