バッチファイル:JScriptを埋め込んでDOSコマンドと変数をやりとりする

前の関連記事:バッチファイル:ファイル名に使える「年月日_時分秒」を1行で得る方法


バッチファイルで日時計算をしようとしたのですがDOSコマンドだけでなんとかしようとすると、うるう年の処理などかなり膨大な処理を強いられることがわかりました。いろいろ調べてみるとバッチファイルの中にJScriptを埋め込むことができることを知りました。

日付計算はいろいろなことを考えなくてはいけない


時刻計算は60進法と24進法の処理をするだけなのですが、日付計算は月毎の日数だけではなくうるう年の判定までしないといけません。

バッチファイルだけでなんとかしている方法をみつけました。

バッチで日付関係の操作
うるう年も考慮して前日の日付を計算する方法

バッチでn日前を求めるには:コマンドプロンプトを使いこなそう!
上記のバッチを参考にn日前の日付を計算しています。

コマンドプロンプト覚え書き
1900年1月1日からの通算日数を算出して計算しています。

うーん、とっても大変そうです。

日付と時刻の計算

いろいろ調べてみるとJScriptでは簡単に日付計算ができることがわかりました。

WSH JScriptを使いこなそう ~ファイル&フォルダ操作~

ファイル操作もJScriptではできそうです。

WSH JScriptを使いこなそう ~アプリケーション操作~

JScriptからDOSコマンドも実行できそうです。

Visual Studio Community 2013をインストールでJScriptもデバッグできそうですし、JScriptで処理しようか、と思っていたらバッチファイル内にJScriptを埋め込まさせることができることを知りました。

バッチファイルからJScriptを呼び出すのはLibreOffice(18)setsdkenv_windows.batを修正するでいじったLibreOffice SDKの環境設定バッチファイルでもやっていたので知っていました。

しかしその方法だとファイルが複数になるので管理が面倒だな、と思っていたのですが一つのファイルにすべて埋め込めると便利に使えそうです。

バッチファイルの中にJScriptを埋め込んで引数を渡す


BATとWSHのコードを1ファイルに混在させるためのshebang記法(複雑なバッチを1ファイルで実現) - プログラミングとIT技術をコツコツ勉強するブログ

このページをみつけたときは信じられませんでしたが実際にやってみるとちゃんとできました。

バッチファイルからJScriptに変数を渡すことは先ほどでてきたsetsdkenv_windows.batを参考にして環境変数を使えばできました。

以下のコードはすべて拡張子batのバッチファイル内に書いたものです。
@if(0)==(0) ECHO OFF
for /F "tokens=1 delims=." %%x in ('^(for /F "tokens=1,2,3 delims=:" %%p in ^('echo %DATE:/=%_%TIME: =0%'^) do echo %%p%%q%%r^)') do set DATE_TIME=%%x
cscript.exe //nologo //E:JScript "%~f0" 
@pause
GOTO :EOF
@end

var WshShell = WScript.CreateObject("WScript.Shell");
var WshSysEnv = WshShell.Environment("process");
var date_time=WshSysEnv("DATE_TIME");
WScript.echo(date_time);
これで前回やった「年月日_時分秒」が環境変数DATE_TIMEでDOSコマンドからJScriptに引き渡してJScriptによって出力できました。
@if(0)==(0) ECHO OFF
for /F "tokens=1 delims=." %%x in ('^(for /F "tokens=1,2,3 delims=:" %%p in ^('echo %DATE:/=%_%TIME: =0%'^) do echo %%p%%q%%r^)') do set DATE_TIME=%%x
cscript.exe //nologo //E:JScript "%~f0" 
@pause
GOTO :EOF
@end

var WshShell = WScript.CreateObject("WScript.Shell");
var date_time=WshShell.ExpandEnvironmentStrings("%DATE_TIME%");
WScript.echo(date_time);
ExpandEnvironmentStrings メソッドを使えばもっと簡単に展開できました。

JScriptからDOSコマンド側に引数を返す


逆にJScriptからDOSコマンドに変数を渡すにはどうしたらよいでしょう?

setsdkenv_windows.batではJScriptからsetコマンドを含んだバッチファイルを書き出してそのバッチファイルを実行して環境変数をsetしています。
@if(0)==(0) ECHO OFF
for /F "tokens=1 delims=." %%x in ('^(for /F "tokens=1,2,3 delims=:" %%p in ^('echo %DATE:/=%_%TIME: =0%'^) do echo %%p%%q%%r^)') do set DATE_TIME=%%x
cscript.exe //nologo //E:JScript "%~f0" 
call var_set.bat
del var_set.bat
echo %DATE_TIME2%
@pause
GOTO :EOF
@end

var WshShell = WScript.CreateObject("WScript.Shell");
var WshSysEnv = WshShell.Environment("process");
var date_time=WshSysEnv("DATE_TIME");
var fso = new ActiveXObject("Scripting.FileSystemObject");
var newFile = fso.CreateTextFile("var_set.bat", true);
newFile.Write(
        "@echo off\n" +
        "set DATE_TIME2=" + date_time + "\n"
        );
newFile.Close();
JScriptで渡したい変数をDATE_TIME2という環境変数にセットするコマンドを含んだvar_set.batというバッチファイルを書き出し、DOSコマンドに戻ったときにそのvar_set.batを実行してDATE_TIME2を代入しています。

この方法は複数の変数を環境変数としてJScriptからDOSコマンドに変数をわたすときに役立つかもしれません。


for /Fコマンドで引数を受け取る方法。
@if(0)==(0) ECHO OFF
for /F "tokens=1 delims=." %%x in ('^(for /F "tokens=1,2,3 delims=:" %%p in ^('echo %DATE:/=%_%TIME: =0%'^) do echo %%p%%q%%r^)') do set DATE_TIME=%%x
for /F %%p in ('cscript.exe //nologo //E:JScript "%~f0"') do set DATE_TIME2=%%p
echo %DATE_TIME2%
@pause
GOTO :EOF
@end

var WshShell = WScript.CreateObject("WScript.Shell");
var WshSysEnv = WshShell.Environment("process");
var date_time=WshSysEnv("DATE_TIME");
WScript.Echo(date_time);
JScriptの出力をDOSコマンドのfor /Fの引数に受けて環境変数DATE_TIME2に代入しています。

引き渡す変数が1つのときはこの方法が簡単です。

JScriptから直接環境変数は設定できないのかと探してみましたがわかりませんでした。

WshShell.EnvironmentのItemプロパティをいじっていたら変数内容が消せなくなって困る


@IT:Windows TIPS -- Tips:WSHで環境変数を設定する

WshShell.EnvironmentプロパティではSYSTEM(システム環境変数)、USER(ユーザー環境変数)、PROCESS(プロセス環境変数)、VOLATILE(一時環境変数)の4種類が設定できるようですが、PROCESSとVOLATILEでは書き込むことができませんでした。

USERで環境変数を書き込むと当然ですがユーザー環境変数に書き込まれてしまって、コントロールパネルの環境変数で削除するまで変数の値が保持されてしまいました、、、というかユーザー環境変数からもシステム環境変数からも削除したのにいまだにecho %DATE_TIME2%で値が出力されるのはどうすればよいのやら、、、
@if(0)==(0) ECHO OFF
cscript.exe //nologo //E:JScript "%~f0" 
echo %DATE_TIME2%
@pause
GOTO :EOF
@end

var WshShell = WScript.CreateObject("WScript.Shell");
var WshSysEnv = WshShell.Environment("system");
WshSysEnv.Item("DATE_TIME2")=""
9行目のsystemをuserとかvolatileとかprocessにして何回か実行しているうちにようやくecho %DATE_TIME2%で値が出力されなくなりました。

もうこのあたりはいじらないようにしよう

WSH JScriptでDOSコマンドのclsに相当するものはないらしい


バッチファイルではclsコマンドを使って画面表示の更新をよく行いますが、バッチファイルに埋め込んだWSH JScriptからDOSコマンドのclsに相当することはうまくできませんでした。

Clear Screen (CLS) Using VBScript - VBScript - Tek-Tips

この議論をみてWshShell.SendKeys("cls~"); (WshShellは WScript.CreateObject("WScript.Shell"))でうまくいくかとやってみましたが、画面がクリアされるのはWSH JScriptがすべて終わったあとでした。

つまりDOSコマンド側に戻ったあとにclsを実行するのと同じことですのでWSH JScript内で画面を更新することができません。

参考にしたサイト


バッチで日付関係の操作
うるう年も考慮して前日の日付を計算する方法

バッチでn日前を求めるには:コマンドプロンプトを使いこなそう!
上記のバッチを参考にn日前の日付を計算しています。

コマンドプロンプト覚え書き
1900年1月1日からの通算日数を算出して計算しています。

日付と時刻の計算
JScriptでの日付計算方法。

WSH JScriptを使いこなそう ~目次~
JScriptについていろいろ解説があります。

BATとWSHのコードを1ファイルに混在させるためのshebang記法(複雑なバッチを1ファイルで実現) - プログラミングとIT技術をコツコツ勉強するブログ
JScriptをバッチファイルに埋め込む方法。

レガシー環境のためのWindows Script Host(WSH)の解説 - Qiita
//E:JScriptでJScriptエンジンを指定し//nologoでCopyrightなどの表示を抑制します。

DATE/TIMEコマンドやDATE/TIME環境変数の形式は地域に依存します。: Windows Script Programming
for /FでJScript部分からDOSコマンド部分に引数を引き渡しています。

Linux - シェル変数と環境変数の違いをコマンドラインで確認する - Qiita
DOSシェル関連の記事では用語が厳密に使い分けされていないように思います。

スーパーユーザーのためのWindowsコマンド再入門:set――環境変数の表示/設定 - ITmedia エンタープライズ
Windowsではシェル変数はなくすべて環境変数になるそうです。

ExpandEnvironmentStrings メソッド
環境変数をJScriptで展開できます。

@IT:Windows TIPS -- Tips:WSHで環境変数を設定する
WshShell.EnvironmentプロパティにはSYSTEM、USER、PROCESS、VOLATILEがあります。

Clear Screen (CLS) Using VBScript - VBScript - Tek-Tips
WSH JScriptでDOSコマンドのCLSに相当するものはないようです。

次の関連記事:バッチファイル:JScript部分をVisual Studio 2013でデバッグする

PR

0 件のコメント:

コメントを投稿