【Windowsバッチ・DOS】バッチファイルの環境変数スコープあれこれ

Windowsユーザーならみんなbatファイル好きだよね。 一度ははまるであろう環境変数のスコープについてあれこれをまとめる。

setコマンド

set 一時環境変数名=値

環境変数を一時設定する。 実行したコマンドプロンプト内でのみ有効。 (他のプロセスからは見えない。該当プロセスから立ち上がった子プロセスはスコープを引き継ぐ。コマンドプロンプト落とすと消える。)

ちなみに、ユーザー環境変数とかシステム環境変数といったものを恒久的に変えたければsetxコマンドを使うそうだ。

setlocalとendlocal

「バッチの中だけでスコープ切りたい!」ってときに使えるコマンド。

set X=outscope

setlocal

echo %X%
rem outscopeと表示される


set X=inscope

echo %X%
rem inscopeと表示される


endlocal

echo %X%
rem outscopeと表示される

pause

ブロック内で環境変数更新

皆がはまったであろう罠。

例えば、forで複数命令実行するときは( ... )で囲んでブロック化する。

for %%i in ( * ) do (
  set FILENAME=%%i
  echo ファイル名は「%FILENAME%」です
)

ところが、上のようにブロック内で環境変数を使った場合、コマンド実行時にfor~ブロック終わりの)までが一度評価されて、以下のように展開される。

for %%i in ( * ) do (
  set FILENAME=%%i
  echo ファイル名は「」です
)

むごい。

回避方法

回避方法を2つ紹介。

setlocal enabledelayedexpansion

setlocal enabledelayedexpansionと宣言すれば、遅延環境変数というものが使える。

setlocal enabledelayedexpansion
for %%i in ( * ) do (
  set FILENAME=%%i
  echo ファイル名は「!FILENAME!」です
)

サブルーチン化

callで別処理に呼ぶと回避できる。

for %%i in ( * ) do (
  call :PRINTNAME %%i
)

goto :END

:PRINTNAME
echo ファイル名は「%1」です
exit /b

:END

pause

【Windowsバッチ・DOS】標準出力・リダイレクト回りまとめ

CUIツールを作ったので色々メモ。

標準出力をファイルにリダイレクト

echo text > stdlog.txt

標準エラーをファイルにリダイレクト

mkdir c:\ 2> errorlog.txt

標準出力と標準エラーをまとめてファイルにリダイレクト

mkdir c:\ > log.txt 2>&1

コンソールにも出力してリダイレクトにも書く

結論から言うと、DOSの標準環境だけじゃ無理。 全部出力し終えてから一気に表示するだけならtypeを使えばよい。

環境は限られるが、 Linuxにteeというコマンドがあり、Windows実装にした「safetee」というツールが有名。

safetee www.vector.co.jp

Linux teeコマンド

【 tee 】 標準入力を標準出力とファイルに出力する | 日経クロステック(xTECH)

2022/08/23 追記:久しぶりにこの周りをいじっていたところ、素晴らしいVBSを公開されているかたがいた。

qiita.com

このスクリプトをShiftJISのtee.vbsとして保存し、「cscript tee.vbs /a sample.log」などと打つと動作する。

【Java】Tar、GZを読み込む

Linux標準の圧縮形式、tar.gz。業務で、Javaの小物を作ることになったのでメモ。

tar.gzの仕組み

2段階に圧縮している。

ファイル
  |
(複数ファイルをTARで1つのバイナリに連結)
  ↓
TARファイル
  |
(1ファイルをGZip圧縮)
  ↓
TAR.GZファイル

Javaのライブラリ

今回は、Java標準のGZIPInputStreamApache Commons CompressのTarArchiveInputStreamを使った。

File outDir = new File("/outdir");
File gzipFile = new File("sample.tar.gz");

try (FileInputStream fis = new FileInputStream(gzipFile)) {
    try (GZIPInputStream gis = new GZIPInputStream(fis)) {
        try (TarArchiveInputStream tis = new TarArchiveInputStream(gis)) {
            for (AchiveEntry entry = tis.getNextEntry(); entry != null; entry = tis.getNextEntry()) {
                if (entry.isDirectory()) {
                    File newDir = new File(outDir, entry.getName());
                    if (!newDir.mkdirs()) {
                        throw new IOException("directory " + newDir.getAbsolutePath() + " cannot create.');
                    }
                } else {
                    File newfile = new File(outDir, entry.getName());
                    File parentDir = newfile.getParent();
                    if (!parentDir.mkdirs()) {
                        throw new IOException("directory " + parentDir.getAbsolutePath() + " cannot create.');
                    }
                    try (FileOutputStream fos = new FileOutputStream(newfile)) {
                        IOUtils.copy(tis, fos);  // Apache common-io
                    }
                }
            }
        }
    }
}

なんだこのネスト。やってることは単純なんだけど。

TarAchiveInputStreamのAPIがやや癖があって、getNextEntryすると、TarArhiveInputStreamのファイルポインタが進む。

また、GZIPInputStreamには作業バッファ長が与えられる。だいたい、デフォルトの8196で十分だが、CPUリソースが余りに余るようであれば増やしてもよいかもしれない。

REST APIの一般的なHTTP Status Code

www.restapitutorial.com

より

まとめると

  • 200 (OK)
  • 成功汎用。Select結果など
  • 201 (Created)
    • リソース作成など。
    • Updateのときもこれなんだろうか?
  • 204 (No Content)

    • リソース削除など。
  • 400 (Bad Request)

    • パラメータ不正、チェック不正など。
  • 401 (Unauthorized)
    • ログイン要求。
  • 403 (Forbidden)
    • アクセス・操作権限なし。
  • 409 (Conflict)

    • 既に登録済みだった、主キー重複など。
  • 500 (Internal Server Error)

    • ハンドリング不可エラー。

これクライアントでこまごま実装するのか。。ちょっと大変だな。

【Java】VisualVMでJavaのプロファイリング

Javaには、「VisualVM」という非常に強力なGUIベースのプロファイラ(どのメソッドでCPUや時間などどれだけのリソースを食ったかを解析するツール)がある。

Home — Project Kenai

シンプルだが非常にわかりやすい。 ローカルで起動してプロセスにアタッチするならどんなjava起動のプロセスでも良いが、 リモートの場合、VM引数追加してしかもポートを開けないとだめなのが難点。

開発には十二分な機能だ。今後活躍してもらおう。

【Java】マニフェストファイルと実行可能JARファイル

ファイル名に「.jar」がついたJARファイルがJavaライブラリの一般的な(ていうか唯一の?)形式。 JARファイルには、自身についてのメタ情報などを記載したマニフェストファイル(META-INF/MANIFEST.MF)という仕組みがある。 (マニフェストファイル、改行しないとダメだの色々フォーマットで口うるさいことで有名なようだ)

(マニュアル) https://docs.oracle.com/javase/jp/1.5.0/guide/jar/jar.html

実行可能JAR

マニフェストファイル中に「Main-Class」、javaコマンドおなじみのメインクラスをはじめから埋め込んだJARファイルを、 「実行可能JAR」と呼ぶそうだ。

つくり方は色々あるらしいが、以下参考できそうなものをリンク参照。

JDK付属ツールでコマンドラインより作成

Jarファイルメモ(Hishidama's java-archive Memo)

Eclipseプラグインから作成

Jarファイルメモ(Hishidama's java-archive Memo)

メインクラスをわざわざ書かなくていいのは素晴らしい。 けど、結局シェル作って

java -jar runnable.jar

ってやらなければいけない。Javaってそんなにスクリプトライクに作りこむ言語仕様じゃないし。あんまり意味ない・・・。

【AngularJS1】$http,$q,Promise回りメモ

$httpサービス

$http | AngularJS 1.2 日本語リファレンス | js STUDIO

非同期なHTTPリクエストを提供してくれるサービス。 例えば、putでURL投げて結果を取得する例。

const url = 'http://api.hostname.com/manapi/user/add';
let data = {
  userid : userid,
  username : username,
  passowrd : password,
};


$http.put(url, data)
    .success(function(data, status, headers, config) {
        let user_no = data.id;
        alert(`ユーザーを登録しました。(ユーザーNo:${user_no}`);
    })
    .error(function(data, status, headers, config) {
        alert('通信に失敗しました。時間をおいて再度ご実行ください。');
    });

jQueryajax()やget()などと機能自体は同じ。

Promiseパターンなオブジェクトを戻り値として返すので、 あとでメモる$qサービスなどと連携して楽に非同期制御が書ける。 (よく、こんな仕組みを考えたものだ。)

$qサービス

AngularJS

非同期処理のユーティリティクラス。

まとめるのがしんどかったのと 非常にわかりやすい記事があったので参考にさせていただいた。

dev.classmethod.jp

こいつが非常に強力で、なるべくdirectiveやcontrollerでは直接サービス依存しないようにしている・・・。

Promise

Promiseとは (※以下はES6のPromiseについての資料です。Angularのとは用法が若干異なります。)

qiita.com

Angularは、Promiseパターンのオブジェクトを独自に提供している。 IE11など、ES6のPromiseを実装していないブラウザでも安心して?使える。

AngularのPromiseもES6と同様に、一般にPromiseパターン、そしてFutureパターン(こちらのほうの性格が強い)を足したような実装になっている。