はじめに
この記事では、Windows のコマンドプロンプト(バッチファイル)で関数や算術演算子を使った計算ができるようになる eval.js を紹介します。
ソースは github に公開しています。
eval.js をコマンドとして実行する方法については、別の記事を参照してください。
eval の機能について
文法
eval [option]... EXPR...
eval [/?] [/help] [/v] [/version]
eval [/syntax] [/sample] [/function]
説明
eval は EXPR を評価した結果を出力します。
結果が true(または数値、文字列など) の場合は、%ERRORLEVEL% に 0 を設定します。
結果が false (または null, NaN) の場合は、%ERRORLEVEL% に 1 を設定します。
式の評価自体に失敗した場合は、%ERRORLEVEL% に 2 以上の値を設定します。
オプション
- /i, /stdin
- 標準入力を eval の変数 $ にセットします。
- /f, /filter
- /i オプションと組み合わせて使用します。 結果が TRUE になった場合だけ $ を出力します。
- /s, /silent
- 結果を出力しません。
- /F
- eval をフィルタモードで実行します。/ifs を指定する場合と等価です。
- /syntax
- eval の文法を表示して正常終了します。
- /sample
- EXPR のサンプルを表示して正常終了します。
- /function
- eval で使用できる関数の一覧を表示して正常終了します。
- /?, /help
- ヘルプを表示して正常終了します。
- /v, /version
- バージョン情報を出力して正常終了します。
一般的な eval との差異
一般的な eval は、引数を1つにまとめてコマンドとして実行しますが、
この eval は Linux における expr , test または find として利用できます。
eval で使用できる値
数値
小数を表現できます。
eval 1.5
=> 1.5
負数を表現できます。
eval -1
=> -1
単位(k, m, g)を付けることができます。
eval 1k
=> 1000
文字列
文字列はシングルクォートで括ります。
eval 'sample string'
=> sample string
文字列の結合ができます。
eval 'abc' + 'def'
=> abcdef
文字列が \ 記号を含む場合はエスケープが必要です。
eval 'C:\\Windows\\'
=> C:\Windows\
先頭に @ を付与することでエスケープ文字を ` 記号に変更することができます。
eval @'C:\Windows\'
=> C:\Windows\
エスケープで表現できる文字は以下の通り。
n 改行
r 復帰
t 水平タブ
' シングルクォート
\ エスケープ文字自身(@ している場合は `)
uFFFF 16進数2バイト文字
\u0022
のダブルクォートは頻繁に使うことになるでしょう。
真偽値
true
と false
の2種類です。大文字・小文字は区別されます。
NULL
null
の 1 種類です。今のところ想定される使い方はありません。
日付
日付は # で括ります。計算に使用できますが、
文字列の生成には向きません(mkdateコマンドを使ってください)。
eval "#2016/5/8#"
=> Sun May 8 00:00:00 UTC+0900 2016
演算
演算子の優先順位を正しく評価できます。
eval 1 + 2 * 3
=> 7
eval (1 + 2) * 3
=> 9
多くの演算子はコマンドプロンプトに解釈されてしまうので
EXPR は基本的にダブルクォートで括ると良いでしょう。
除算演算子は、コマンドへのオプションとなってしまうためクォートが必要です。
eval "10 / 7"
=> 1.4285714285714286
論理演算子は、コマンドプロンプトの式になってしまうためクォートが必要です。
eval "true && false"
=> false
eval "false || true"
=> true
比較演算子は、出力のリダイレクトになってしまうためクォートが必要です。
eval "100 > 10"
=> true
論理演算子は2種類(&, && または |, ||)ありますが、区別はありません。
また、両方ともショートサーキットです。
eval "file('abc.txt') & size('abc.txt') > 1k"
eval "file('abc.txt') && size('abc.txt') > 1k"
=> true(or false) 同じ結果になる。
また、'abc.txt' が存在しない場合 file() が false となるので、
size() は評価されない。よって size() でエラーは発生しない。
関数の詳細については /function オプションを参照してください。
eval の使用例
条件分岐の可読性を高める
eval の関数を使用することで可読性の高い条件分岐を記述することができます。
eval は式が true となるとき環境変数 %ERRORLEVEL% に 0 をセットします。
:: 二つの条件を IF を入れ子にせず記述できる
eval "file(@'file.txt') && size(@'file.txt') > 1k"
IF %ERRORLEVEL% EQU 0 goto hogehoge
:: OR 条件の複数条件にも対応できる
eval "file(@'file.txt') || dir(@'folder')"
IF %ERRORLEVEL% EQU 0 goto hogehoge
:: 複雑な条件を複数行に分けて記述する場合(実行コストは高くなるでしょう)
eval "%ERRORLEVEL% == 0 && file(@'file.txt')"
eval "%ERRORLEVEL% == 0 && size(@'file.txt') > 1k"
eval "%ERRORLEVEL% == 0 && adate(@'file.txt') > #2016/05/10#"
eval "%ERRORLEVEL% == 0 && length(fullpath(@'file.txt')) <= 255"
IF %ERRORLEVEL% EQU 0 goto hogehoge
複雑な数値計算
eval は複雑な数値計算にも対応できます(JScriptの計算精度に依存します)。
eval "1 + 2 * 3 + (4 % 5) / pow(6, 7)"
=> 7.0000142889803385
計算結果の取得は、これまで通り FOR を使ってください。
フィルタ
eval は標準出力のフィルタとして利用できます。
以下の例は、標準出力から読み込んだファイルとフォルダの一覧から
1000バイト以上のファイルだけを出力します。
$ は標準入力が代入される eval コマンド唯一の変数です。
dir /s /b | eval "file($) && size($) > 1k" /ifs
関数
ファイルシステム
- file(STRING)
- STRING で指定されたファイルが存在する場合は true を返します。
- dir(STRING)
- STRING で指定されたフォルダが存在する場合は true を返します。
- empty(STRING)
- STRING で指定されたファイルまたはフォルダが空の場合に true を返します。
- size(STRING)
- STRING で指定されたファイルのサイズを返します。
- cdate(STRING)
- STRING で指定されたファイルの作成日時を返します。
- mdate(STRING)
- STRING で指定されたファイルの更新日時を返します。
- adate(STRING)
- STRING で指定されたファイルのアクセス日時を返します。
文字列
- length(STRING)
- STRING で指定された文字列の長さを返します。
- to_n(STRING)
- STRING を数値に変換します。
- slice(STRING, NUMBER1[, NUMBER2])
- STRING を NUMBER1 文字目以降を切り出した STRING を返します。
- NUMBER2 を指定すると、NUBMER1 から NUMBER2 文字目を切り出した STRING を返します。
- indexof(STRING1, STRING2)
- STRING1 の中に STRING2 があるか検索します。発見した位置(Number)を返します。
- 発見できなかった場合は -1 を返します。
- upper(STRING)
- STRING を大文字にして返します。
- lower(STRING)
- STRING を小文字にして返します。
数学
- sqrt(NUMBER)
- NUMBER の平方根を返します。
- pow(NUMBER1, NUMBER2)
- NUMBER1 を NUMBER2 のべき乗で返します。
- round(NUMBER)
- NUMBER を四捨五入した値を返します。
- floor(NUMBER)
- NUMBER の小数部を切り捨てた値を返します。
- ceil(NUMBER)
- NUMBER の小数部を切り上げた値を返します。
- sin(NUMBER)
- NUMBER の sin 値を返します。NUMBER はラジアンです。
- cos(NUMBER)
- NUMBER の cos 値を返します。NUMBER はラジアンです。
- tan(NUMBER)
- NUMBER の tan 値を返します。NUMBER はラジアンです。
日付
- today()
- システム日付を返します。
おわりに
日付計算できるようにしたい。