cmd.exeでパイプを使う場合の注意点

Windowsのcmd.exeでパイプを使う場合の注意点について書きます。*1

cmd.exeのパイプ

以下の2つのコマンド実行は、基本的に同じ動作となります。(前者はパイプ、後者は一時ファイルを使用)

  • コマンドA | コマンドB
  • コマンドA > tmp & コマンドB < tmp

しかし、扱うデータによっては、2つの間で結果に違いが出る場合があります。*2

テスト1

初めに、結果に違いが出ないケースをテストします。次の3つのコマンド実行を見てください。

C:\>echo %OS%
Windows_NT

C:\>echo %OS% | more
Windows_NT

C:\>echo %OS% > tmp & more < tmp
Windows_NT
1番目
環境変数OSの値を、単純に表示します。
2番目
環境変数OSの値を、パイプを経由してmoreで表示します。
3番目
環境変数OSの値を、一時ファイルを経由してmoreで表示します。

表示結果は、どれも「Windows_NT」で同じになりました。*3

テスト2

テスト1の場合は環境変数OSの値を表示しましたが、今度は「%OS%」という文字列を表示します。特殊文字の%をエスケープするので、echoの後は「^%OS^%」となります。実行結果は次のようになります。

C:\>echo ^%OS^%
%OS%

C:\>echo ^%OS^% | more
Windows_NT

C:\>echo ^%OS^% > tmp & more < tmp
%OS%

1番目と3番目では、想定どおりに「%OS%」が表示されました。しかし、2番目のパイプを経由したケースでは、なぜか「%OS%」が展開されて、「Windows_NT」が表示されました。

テスト3

今度はパイプを経由したケースでも「%OS%」と表示させるため、さらに特殊文字エスケープして、echoの後を「^^^%OS^^^%」としてみます。実行結果は次のようになります。

C:\>echo ^^^%OS^^^%
^%OS^%

C:\>echo ^^^%OS^^^% | more
%OS%

C:\>echo ^^^%OS^^^% > tmp & more < tmp
^%OS^%

2番目のパイプを経由したケースで「%OS%」が表示されました。しかし、当然のことながら、1番目と3番目では余分なエスケープ文字が付いて「^%OS^%」と表示されました。

まとめ

cmd.exeでパイプを使うと、データ中の「%環境変数%」が展開されます。(遅延展開が有効な場合は、「!環境変数!」も展開されると思われます。) 処理対象のデータに「%」や「!」が含まれる場合は、注意が必要です。場合によっては、一時ファイルを使ったほうがよいかもしれません。

*1:Windows XP SP3で確認しました。

*2:一時ファイルが残るのは、無視して考えます。

*3:実際には、パイプ経由の場合は改行が1つ多いのですが、話の大筋に関係しないので無視します。