LoginSignup
1
3

More than 5 years have passed since last update.

バッチファイルで複雑な数値計算をする - eval.js

Last updated at Posted at 2016-05-14

はじめに

この記事では、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 のダブルクォートは頻繁に使うことになるでしょう。

真偽値

truefalse の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()
システム日付を返します。

おわりに

日付計算できるようにしたい。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3