コマンドプロンプトの REM はコマンド

気付いていませんでした。

コマンドプロンプトのバッチ処理ファイルでコメントを書くときに REM を使いますが REM はコメントのマークではなく 「何もしない」コマンドでした。

C:\> REM コメント!

"/?" を付けるとヘルプも表示されます。

C:\> REM /?

バッチ ファイルまたは CONFIG.SYS にコメント (注釈) を記録します。

REM [コメント]

なので、次のような "/?" で始まる変な装飾を付けてしまうと。

REM /???? -- コメント -- ???/
C:\> test.bat

-- の使い方が誤っています。

このようにエラーが出てしまいます。

コマンドプロンプトの FOR コマンドの出力をまとめる

FOR コマンドは処理を繰り返すことができます。

次のサンプルは、aaaa.txt の内容を行ごとに ダブルクォーテーションで囲んで出力しています。

C:\> FOR /F %I IN (aaaa.txt) DO @ECHO "%I" >> bbbb.txt

これは次のように書くことができます。

C:\> (FOR /F %I IN (aaaa.txt) DO @ECHO "%I") > bbbb.txt

こうすることで、ファイルを空にする処理が不要になったり 処理の速度が上がったりします。

コマンドプロンプトの DIR コマンドでファイルだけ出力する

コマンドプロンプトの DIR コマンドで ファイルだけを出力するときは 「/A」オプションで「ディレクトリ以外」を指定します。

C:\> DIR /A:-D

海外の顔文字みたいになってますが 「D」がディレクトリで、「-」が〇〇以外になります。

コロンは省略することができます。

C:\> DIR /A-D

「/B」オプションを付けてファイル名だけ、 なんてこともできます。

C:\> DIR /A:-D /B

コマンドプロンプトで SH1 や MD5 のハッシュ値を求める

この前の CERTUTIL を使うと ファイルのハッシュ値も求めることができます。

C:\> CERTUTIL -hashfile test.txt SHA1
SHA1 ハッシュ (ファイル decoded.txt):
05 f6 94 17 04 da 46 18 40 dd da a0 a8 87 0c 9a 21 cb 6e 17
CertUtil: -hashfile コマンドは正常に完了しました。

C:\> CERTUTIL -hashfile test.txt MD5
MD5 ハッシュ (ファイル decoded.txt):
77 c1 6d 26 74 1b 41 91 c9 25 8b 59 61 a0 c4 d3
CertUtil: -hashfile コマンドは正常に完了しました。

不要な行を FIND コマンドで取り除きます。

C:\> CERTUTIL -hashfile test.txt SHA1 | FIND /V ":"
05 f6 94 17 04 da 46 18 40 dd da a0 a8 87 0c 9a 21 cb 6e 17

間の空白も取り除きます。 FOR コマンドだと簡単です。

C:\> @FOR /F "delims=/" %i IN ('CERTUTIL -hashfile test.txt SHA1 ^| FIND /V ":"') DO @((SET ITEM=%i) && (ECHO %ITEM: =%))
05f6941704da461840dddaa0a8870c9a21cb6e17

何かに使えそうですね。

コマンドプロンプトで base64 ファイルをデコードする

Windows のコマンドプロンプトには CERTUTIL というコマンドがあります。 証明書とかをアレコレするコマンドなのですが このコマンドを使うことで base64 ファイルのデコードができます。

[参考]
Windowsコマンド集 - certutil:ITpro

まず Linux で base64 エンコードしたファイルを作ります。 (別にLinuxで作る必要はありません)

$ sudo vi source.txt

$ cat source.txt
おはよう
こんにちは
こんばんは

$ cat source.txt | nkf -s | base64 | tee encoded.txt
gqiCzYLmgqQKgrGC8YLJgr+CzQqCsYLxgs6C8YLNCg==

このファイルを Windows に持ってきて デコードしてみます。

C:\> CERTUTIL -decode encoded.txt decoded.txt
入力長 = 44
出力長 = 31
CertUtil: -decode コマンドは正常に完了しました。

C:\> TYPE decoded.txt
おはよう
こんにちは
こんばんは

CERTUTIL コマンドでエンコードもできます。

C:\> CERTUTIL -encode decoded.txt encoded.txt
入力長 = 31
出力長 = 102
CertUtil: -encode コマンドは正常に完了しました。

C:\> TYPE encoded.txt
-----BEGIN CERTIFICATE-----
gqiCzYLmgqQKgrGC8YLJgr+CzQqCsYLxgs6C8YLNCg==
-----END CERTIFICATE-----

コマンドプロンプトの標準出力をクリップボードに保存する

Windows のコマンドプロンプトには、 コマンドの結果などの標準出力をクリップボードに保存するための CLIP というコマンドがあります。

使い方も簡単で パイプやリダイレクトで渡すだけです。

C:\> DIR | CLIP
C:\> CLIP < README.TXT

コマンドの結果をファイルに保存したり、 コマンドプロンプトのウィンドウを範囲選択する必要もないため ちょっとした作業で活躍してくれるコマンドです。

コマンドプロンプトでファイルをまとめて連結する

コマンドプロンプトの COPY コマンドでは 次のように + を使うことで複数のファイルを連結することができます。

C:\> COPY /B 1.txt + 2.txt + 3.txt all.txt

ちなみに B オプションは ファイルをバイナリファイルとして扱う指定です。

フォルダに多数あるファイルを連結するとき いちいち + を書くのは大変です。 次のようにワイルドカードでファイルを指定しても連結することができます。

C:\> COPY /B *.txt all.txt

連結する順番がファイル順のときは こっちの方が簡単ですね。

Windows の TIMEOUT コマンド

下の記事でしったのですが、Windows Vista/2003 Server から TIMEOUT というコマンドが標準で入っているそうです。

[参考]
timeout/sleepコマンドで実行を一時停止する − @IT

TIMEOUT は Linux の sleep のようなコマンドで 指定した時間待機させることができます。

C:\> TIMEOUT /T 3

3 秒待っています。続行するには何かキーを押してください ...

メッセージの通り、キーを押すことで次に進むことができます。

オプション "/NOBREAK" で [Ctrl]+C 以外のキー入力を 無効にすることができます。

C:\> TIMEOUT /T 3 /NOBREAK

3 秒待っています。終了するには CTRL+C を押してください ...

これまでコマンドプロンプトで待機させるときは コマンドを入れるか ping を使っていたので TIMEOUT の登場は嬉しいですね。

メッセージを出したくないときは nul に捨てます。

C:\> TIMEOUT /T 3 /NOBREAK > nul

nul は /dev/null みたいなものです。

コマンドプロンプトでも PUSHD

以前 Bash の pushd について書きましたが コマンドプロンプトでも pushd を使うことができます。

C:\> PUSHD D:\test
D:\test> POPD
C:\> 

このようにドライブも移動してくれます。

面白いのがネットワークドライブのパスを指定したときです。

C:\> PUSHD \\192.168.1.15\public
Z:\> 

このように Z から順に空いているドライブを探して 一時的にネットワークドライブの割り当てをしてくれます。 (マイコンピュータを見ると、割り当てられたドライブ名が表示されています)

POPD や、コマンドプロンプトを EXIT して 一時的に割り当てられたドライブを抜けると ネットワークドライブの割り当ても自動で解除されます。

FTP コマンドで、接続先サーバのファイルの属性を変更する

FTP コマンドで 接続先サーバのファイルの属性を変える場合 "quote site" コマンドを使用します。

まずは FTP サーバに接続します。

C:\> ftp 192.168.1.100

quote site コマンドの後ろは 通常の chmod コマンドのように 「属性」「ファイル名」を指定します。

ftp> quote site chmod 755 test.txt

使い方はこれで終わりですが 実はこれは FTP サーバ側で chmod の使用がサポートされている必要があります。

そもそも quote は 接続先に直接コマンドを送信するコマンドで site は、接続先でサポートしているコマンドを 実行するコマンドなのです。

chmod がサポートされているかどうかは "quote site" の後ろに "help" を指定して確認します。

ftp> quote site help

214- The following SITE commands are recognized (* =>'s unimplement
   UMASK   IDLE    CHMOD   HELP
214 Direct comments to ftp-bugs@KURO-BOX1.

上の例の FTP サーバでは chmod の他にも umask、idle が サポートされています。
( * が付いている場合はサポートされていません)

Vista ではコマンドプロンプトにドラッグ&ドロップできない

Windows Vista では XP までのように ファイルをコマンドプロンプトにドラッグ&ドロップして ファイルのパスを貼ることができません。

方法が無いかと検索してみると次のような記事がありました。

【参考サイト】
ここが変わったWindows Vista 100連発! ― 第49回 “パスとしてコピー”でコマンドプロンプトにパス名を渡す

これによると Vista では [Shift] キーを押しながら右クリックすると 次のように「パスとしてコピー」するメニューが出てくるので これでファイルのパスをコピーしてから コマンドプロンプトに貼り付けるそうです。

WRITE_0275_01

ドラッグ&ドロップが便利だったので残念です。

コマンドプロンプトの遅延環境変数

コマンドプロンプトで FOR ループなどを使っているときに 「あれ? 変数の値が変わらない??」ということがあります。

例えば、バッチファイルに次のように書いてあるとします。

FOR /F %%i IN ('SET') DO ECHO %%i 

これは、コマンド SET の実行結果をずらっと表示します。

この結果の件数を取得するためにカウンタを付けたとします。

SET COUNT=0
FOR /F %%i IN ('SET') DO SET /A COUNT=%COUNT%+1
ECHO %COUNT% 

上手く行きそうなのですが、結果は 1 が出力されます。

これは変数の“即時展開”というもので、 ループの中の %COUNT% が先に評価されてしまうので 結果的には次のような処理になってしまうためです。

SET COUNT=0
FOR /F %%i IN ('SET') DO SET /A COUNT=0+1
ECHO %COUNT% 

対応として“遅延環境変数”を使うという方法があります。

遅延環境変数は、名前の通り遅延して変数を評価してくれるわけですが デフォルトではオフ、CMD.exe のオプションやレジストリの変更や SETLOCAL での指定が必要になります。
(詳しくは CMD /? してください)

今回は SETLOCAL を使って見ます。

次のように SETLOCAL で enabledelayedexpansion を指定して ENDLOCAL で終わります。 ( ENDLOCAL は省略可です。)

さらに遅延評価する変数は "%" ではなく "!" で囲みます。

SETLOCAL enabledelayedexpansion
SET COUNT=0
FOR /F %%i IN ('SET') DO SET /A COUNT=!COUNT!+1
ECHO %COUNT%
ENDLOCAL

これで想定していた結果が返ります。
(試す場合はファイルに保存して実行してください)

遅延環境変数を使わないで CALL を使う方法もあります。

SET COUNT=0
FOR /F %%i IN ('SET') DO CALL SET /A COUNT=%%COUNT%%+1
ECHO %COUNT%

これでも同じ結果が返ります。
CALL の中で "%" が二重になっていることに注意してください。

コマンドプロンプトで計算する

コマンドプロンプトは計算もできます。

計算には、SET コマンドの /A オプションを使います。

C:\> SET /A RESULT=1+2*4+5
14

C:\> ECHO %RESULT%
14

直接実行した場合は、計算結果が出力されますが バッチファイルに書いた場合は出力されません。

演算子は次のものが使えます。

()                  - グループ化
! ~ -               - 単項演算子
* / %               - 算術演算子
+ -                 - 算術演算子
<< >>               - 論理シフト
&                   - ビット演算子 AND
^                   - ビット演算子排他的 OR
|                   - ビット演算子 OR
= *= /= %= += -=    - 代入
  &= ^= |= <<= >>=
,                   - 式の区切り記号 

">" が含まれる場合は リダイレクトにならないように ダブルクォーテーションで囲みます。

C:\> SET /A RESULT="14>>2"
3

代入する変数を宣言せずに、計算だけすることもできます。

C:\> SET /A 13*2+1
27

先頭が 0 の場合は、8 進数、0x の場合は 16進数になります。

C:\> SET /A 011+0xA
19

上の例は、10 進数の 9 と 10 を足しています。

コマンドプロンプトで文字列を置換する

コマンドプロンプトでも、簡単な文字列置換が可能です。

例えば、次のような変数 DATE を宣言します。

C:\> SET DATE=2010/03/20
C:\> ECHO %DATE%
2010/03/20

"/" を "-" に置換します。

C:\> ECHO %DATE:/=-% 
2010-03-20

書式は "%変数:置換される文字=置換する文字%" です。

"*" を使うと、"*" 以降が一致するところまでを置換できます。
ただし "*" は先頭にしか使えません。

C:\> ECHO %DATE:*/=YEAR%
YEAR03/20

上の例では、最初に出てくる "/" までを置換対象としています。

置換する文字列を指定しないと 空文字を指定したことになります。

C:\> ECHO %DATE:*/=%
03/20

コマンドプロンプトで 0 バイトのファイルを作成する

なんとなく使っている方法のメモです。

C:\> TYPE nul > zero.txt

コマンドプロンプト キーボードだけでペーストする

「コマンドプロンプトで、キーボードだけで クリップボードのテキストをペーストできませんか?」と 聞かれました。

私は、マウスとショートカットを組み合わせて使うのが好きなので あまり気にならないのですが、キーボードユーザは マウスに持ち替えるのが、好きではないようです。

ちょっと考えてみました。

編集 → 貼り付けは、下の図のように ウィンドウの左上のアイコンからも呼び出せます。

WRITE_0167_01

意外と知られていないようなのですが [Alt+Space] で、ウィンドウの左上のアイコンのメニューを 呼び出すことができます。

これを使います。

あとは、普通に [E] (編集)と [P] (貼り付け)を押します。

1アクションでは無理だったのですが キーボードユーザには マウスを使わなくて済むだけで充分なようで 満足してもらえました。

慣れてくると [Alt+Space] [E] [P] とリズム良く押せます。 何でも疑問に思うことは大事ですね。

コマンドプロンプトで、ファイルの内容が変わっていれば置き換える

"old.txt" と "new.txt" があり、内容が変わっていれば "new.txt" で置き換えて 変わっていなければ そのまま(タイムスタンプを変更したくない)というような 処理を行います。

つまり、次のような処理になります。

  • 内容が違う → "old.txt" を "new.txt" で置き換え
  • 内容が同じ → "new.txt" を削除

ファイルの比較は、FC コマンドを使用します。

FC コマンドは、比較した結果が「一致」の場合、正常終了、 「不一致」の場合は、異常終了となるので、それを利用して 次のようなコマンドを作成します。

C:\> fc /B "old.txt" "new.txt" > nul 2>&1 && ^
More? del "new.txt" || ^
More? move /Y "new.txt" "old.txt"

コマンドが長いので折り返していますが、1 行のコマンドです。

実行すると、結果的に "old.txt" が 1 つだけ残ります。

"old.txt" と "new.txt" が変わってるだけでなく、 "old.txt" が存在しない場合も "new.txt" で置き換えます。

ファイルを指定して実行しましたが、これを使ってバッチ処理を作れば フォルダ単位で同じ名前のファイルを比較して置き換え、といったこともできます。 サーバ間の移動などを行うときに、最新版のファイルだけを移動して、既存のファイルは タイムスタンプを更新したくない、といったときなどに使えそうです。

コマンドプロンプトで Linux の du っぽいコマンドを作ってみる

後輩が コマンドプロンプトで du っぽいことがしたいができないと 言っていたので、コマンドプロンプトの奥深さを理解してもらおうと ちょっと考えてみました。

Windows XP で動作確認しました。 Windows 2000 では、ディレクトリのパスにマルチバイト文字が 含まれていると うまく動かないときがあります。

@ECHO OFF

SET DIROPTION=/A:-D
SET CURRENTPATH=%CD%
SET TARGETPATH=%~1
IF "%TARGETPATH%"=="" SET TARGETPATH=%CURRENTPATH%

CD /D %TARGETPATH%

FOR /R %%i IN (.) DO (
    FOR /F "usebackq tokens=1,3" %%j IN (
        `DIR %DIROPTION% /-C "%%~fsi" 2^>nul ^|
         FINDSTR "個のファイル.*バイト$"`
    ) DO (
        ECHO "%%~fi",%%j,%%k
    )
)

CD /D %CURRENTPATH%

これを du.bat として保存します。

引数に対象のディレクトリを指定できます。 指定しない場合、カレントディレクトリが対象となります。

C:\> du.bat D:\wwwroot

"D:\wwwroot",1,19001
"D:\wwwroot\css",7,106837
"D:\wwwroot\img",13,2685964 

出力結果は、パス、ファイル数、合計ファイルサイズです。

このスクリプトは、ファイル数が 0 のディレクトリは 処理負荷を減らすために出力しないようにしています。 ファイル数が 0 のディレクトリも出力するには 3 行目の設定を次のように変更します。

SET DIROPTION=/A:-

コマンドプロンプトの文字色・背景色を変更する

COLOR というコマンドで コマンドプロンプトの文字と背景の色を 変えることができます。

C:\> COLOR 2F

16 進数 2 桁 で指定します。 ひと桁目(上の例では "2")が 背景色、 ふた桁目(上の例では "F")が 文字色です。

色の値は、次のようになります。

 0 = 黒          8 = 灰色
 1 = 青          9 = 明るい青
 2 = 緑          A = 明るい緑
 3 = 水色        B = 明るい水色
 4 = 赤          C = 明るい赤
 5 = 紫          D = 明るい紫
 6 = 黄色        E = 明るい黄色
 7 = 白          F = 輝く白

次のように 値が1つの場合は 文字色が変更されます。

C:\> COLOR 2

次のように 文字と背景の色に 同じ色を指定した場合は 文字が見えなるためなのか 変更されません。

C:\> COLOR 22

初期値に戻すには 次のように引数無しで実行します。

C:\> COLOR

バッチ処理の中では、この「初期値に戻す」は使えないようです。

コマンドプロンプトのタイトルを変更する

Windows 2000/XP から コマンドプロンプトは TITLE コマンドで ウィンドウのタイトルを変えることができるようになりました。

@ECHO OFF

TITLE コマンドプロンプトで何をしているかわかりやすい!
PAUSE

これを実行すると 次のようになります。

時間のかかる処理のときなど コマンドプロンプトのタイトルを変えておけば 何の処理をしているかわかりやすくなります。

ファイルを 0 バイトにする

追記型でログファイルなどを作成していると ファイルを 0 バイトでクリアしたいときがあります。

次ようなコマンドで ファイルを 0 バイトにします。 (ファイルが存在しなければ、 0 バイトのファイルを作成します)

$ cat /dev/null > 0.txt

DOS の場合は、次のようにコマンドを打ちます。 null ではなく、nul なので注意してください。

C:\> type nul > 0.txt

DOSでネットワーク上のフォルダにアクセスする

DOSでネットワーク上のフォルダにアクセスしようとすると 下のようにエラーが発生します。

C:\>cd \\192.168.1.10\share
CMD では UNC パスは現在のディレクトリとしてサポートされません。 

そこで、SUBST コマンドを使用します。

C:\>SUBST Z: \\192.168.1.10\share
C:\>Z:
Z:\>

SUBST は、仮想ドライブを割り当てるコマンドです。 上の場合は 「\\192.168.1.10\share」を「Zドライブ」として設定しました。

これで、ネットワーク上のフォルダもローカルと同じように DOSからアクセスすることができます。

割り当てを解除するときは、下のようにコマンドを打ちます。

C:\>SUBST Z: /D

FORコマンド中でパイプ&リダイレクトを使用する

DOSのFORコマンドは、数あるDOSのコマンド中でも 肝となる重要なコマンドです。

そのFORコマンド内で実行するコマンドに パイプやリダイレクトを使用したい場合があります。

例えば・・・

C:\>FOR /F %i IN ('DIR /B /A:-D | FIND /C /V ""') DO ECHO %i
| の使い方が誤っています。

上の例では、カレントディレクトリのファイルの数を出力しようとしているのですが 「| の使い方が誤っています。」とエラーが表示されてしまいます。

これは、FORコマンド内のパイプやリダイレクトは "^"(キャレット)を使ってエスケープしてやる必要があるためです。

正しくは、下のようになります。

C:\>FOR /F %i IN ('DIR /B /A:-D ^| FIND /C /V ""') DO ECHO %i
3

リダイレクトも同様です。

FOR /F "tokens=1,2 delims==" %i IN ('ASSOC') DO (
  IF NOT "%j" == "" (
    FOR /F "tokens=2 delims==" %k IN ('FTYPE %j 2^>nul') DO (
      ECHO %i
      ECHO  -^> %k
      ECHO.
    )
  )
)

上の例は、ファイルの関連付けを出力しているのですが、 3行目の標準エラーを捨てる「2^>nul」の「>」も エスケープしています。

MS-DOSのバッチファイルに、WSH(JScript)のコードを記述する

WSHには、標準入力からスクリプトを受け取ることができないので DOSの処理と、WSHの処理が必要な場合は、2つのファイルが必要になります。

今回は、ちょっと変わった手で1つのファイルで実行します。

@if (1==1) /*
@ECHO OFF
rem ========================================================
rem = MS-DOS 処理
rem ========================================================
:DOS
ECHO I'm MS-DOS!

:JSCRIPT
CScript //Nologo //E:JScript "%~f0" %*

GOTO :EOF
rem */
@end

/** ========================================================
  *  JavaScript 処理
  * ========================================================
 **/
// 主処理の呼び出し
WScript.quit(main(WScript.arguments.length
                , WScript.arguments));

// 主処理
function main( argc, argv ) {
    WScript.echo("I'm JScript!");
}

これを test.bat として実行すると、以下のような結果になります。

C:\>test.bat
I'm MS-DOS!
I'm JScript!

DOSの処理中に同じファイルをJScriptとして処理させています。

ポイントは先頭の「@if」から「@end」までです。 「@if」は、条件付きコンパイラというものなのですが、 この先頭が「@」なので、DOSの「@」と共存できているのです。

1行目の「/*」で、JScriptは「*/」までコメントになります。 逆にDOSの方は「GOTO :EOF」で処理終了になるので、 前半がDOS、後半がJScriptの処理を記載できます。

WSH(JScript)の起動時にDOSで受けた引数もすべて渡していますので それを元に処理することも可能です。

以下は、簡単なサンプルです。

@if (1==1) /*
@ECHO OFF
rem ========================================================
rem = MS-DOS 処理
rem ========================================================

rem 書式設定
SET SCRIPT=CScript //Nologo //E:JScript "%~f0"

rem 処理日取得
FOR /F %%i IN ('%SCRIPT% "%%m/%%d"') DO SET TODAY=%%i

rem 処理日出力
ECHO 今日は%TODAY%です。

GOTO :EOF
rem */
@end

/** ========================================================
  *  JavaScript 処理
  * ========================================================
 **/
// 主処理の呼び出し
WScript.quit(main(WScript.arguments.length
                , WScript.arguments));

// 書式付日付取得処理
function getDate( fmt ) {
    function _zero( val, len ) {
        for ( var i = 0; i < len; i++ ) {
            val = "0" + val;
        }
        return val.substr( val.length - len, len );
    }
    if ( ! fmt ) fmt = "%Y/%m/%d %H:%M:%S";
    var now = new Date();
    fmt = fmt.replace( "%Y", now.getFullYear() );
    fmt = fmt.replace( "%m", _zero(now.getMonth() + 1, 2) );
    fmt = fmt.replace( "%d", _zero(now.getDate() + 1, 2) );
    fmt = fmt.replace( "%H", _zero(now.getHours() + 1, 2) );
    fmt = fmt.replace( "%M", _zero(now.getMinutes() + 1, 2) );
    fmt = fmt.replace( "%S", _zero(now.getSeconds() + 1, 2) );
    return fmt;
}

// 主処理
function main( argc, argv ) {
    if ( argc > 0 ) {
        WScript.echo( getDate( argv(0) ) );
    } else {
        WScript.echo( getDate() );
    }
}

実行結果は以下のようになります。

C:\>test.bat
今日は02/27です。

DOSでは難しい書式付の日付をJScriptで作成してみました。

MS-DOSでテキストの内容を行番号付きで表示する

DOSには、Linuxの「cat -n」のように テキストデータに 行番号を付けて表示するコマンドがありません。

今回は、FIND コマンドを使って実現してみます。

FIND コマンドは、ファイルや標準入力の内容から キーワードが含まれる行を返してくれるコマンドです。 正規表現が使えない grep コマンドみたいなものです。

たとえば、下のようなテキストファイル test.txt があります。

あいうえお
カキクケコ
さしすせそたちつてと
 なにぬのの
  はひふへほ
や
ゆ
よ
らりるれろ
わおん

TYPE コマンドで開いて、FIND コマンドにパイプします。

C:\>TYPE test.txt | FIND /N /V "/////"
[1]あいうえお
[2]カキクケコ
[3]さしすせそたちつてと
[4] なにぬのの
[5]  はひふへほ
[6]や
[7]ゆ
[8]よ
[9]らりるれろ
[10]わおん

各行に行番号が付いて出力されました。

FIND コマンドの /N は、行番号を付けるオプション。 /V は、条件に“一致しない”場合に結果を返すオプションです。

つまり、テキストデータの中に絶対に存在しない文字列を条件にして 「それ以外の行」=「全ての行」を取得しているわけです。

MS-DOSでコマンドの実行結果を変数に入れる

UNIX/Linuxでは、コマンドの実行結果は簡単に変数に入れることができますが DOSでは、ちょっと工夫が必要です。

といっても、慣れれば呪文みたいなものなのです。 呪文のカギは FOR コマンドです。 下のサンプルでは、「TIME /T」の結果を ローカル変数 NOWTIME に入れています。

C:\>FOR /F "usebackq" %t IN (`TIME /T`) DO SET NOWTIME=%t
C:\>ECHO NOWTIME=%NOWTIME%
NOWTIME=21:57

/F は、IN の結果やリストを1行ずつ処理するオプションです。 1行ごとに DO 以下のコマンドを繰り返すわけですが、 コマンドの実行結果が1行なので、1回だけ値がセットされます。

"usebackq" は、 コマンド文の囲みに、"`"(バッククォーテーション)を 使用するオプションです。 このオプションを付けない場合、下のように シングルクォーテーションで、 コマンドを囲みます。

C:\>FOR /F %t IN ('TIME /T') DO SET NOWTIME=%t

UNIX/Linux のように「コマンドの実行はバッククォーテーションだよね」って 人は、このオプションを付けてください。

バッチファイルに書くときは、下のように書きます。

@ECHO OFF
FOR /F "usebackq" %%t IN (`HOSTNAME`) DO SET HNAME=%%t
ECHO %HNAME%

FOR コマンド内の "%" は "%%" にしなくてはなりません。

HOSTNAME は、 ホスト名を出力するコマンドです。 WindowsXP以上で、インターネットプロトコル(TCP/IP)が インストールされていると使用できます。 (ホスト名が欲しいだけならば、環境変数 %COMPUTERNAME% もあります)

拡張子を省略しても実行できるワケ

DOSプロンプトでは、 exeの実行ファイルや、 batのバッチファイルは、 拡張子を省略しても実行することができます。

省略して実行できる拡張子は 環境変数 PATHEXT で、定義されています。 コマンドプロンプトで、以下のように打って調べます。

C:\>SET PATHEXT
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH

SET は、 環境変数を設定・参照するコマンドです。 引数に環境変数名を付けると、その値を表示することができます。 引き数を付けないと、全ての環境変数と値を表示します。

以下のように拡張子だけ違うファイルがある場合、 ファイル名だけで実行すると、 環境変数 PATHEXT で 定義されている順番で実行します。

C:\>DIR /A:A /B
test.bat
test.vbs
test.wsh

C:\>test
I'm test.bat!  ← test.bat が実行された

この場合、test.com(無い)→ test.exe(無い)→ test.bat(有る)の順番で探します。 もし、test.bat を削除すると、次の検索順の test.vbs が実行されるわけです。

新しく省略したい拡張子がある場合は、この環境変数 PATHEXT に 追加すると、拡張子なしで実行できるようになります。

ちなみに検索するパス(場所)は、環境変数 PATH に 定義されている順番です。 つまり、PATH で定義されている検索するパスの順番に、 PATHEXT で定義されている拡張子の順番で探していくわけです。

簡単にフォルダのツリー図を作成する

今日紹介するのは、DOSコマンドを使って 簡単にフォルダのツリー図を作成する小ネタです。 (テレビショッピングのノリで)

まずは、以下の内容で「ctree.bat」を作成します。 別にバッチファイルを作成する必要は無いのですが せっかくなのでいつでも使えるようにファイルに しておきます。

余談ですが、バッチファイル名を コマンドと同じ(tree.bat)のようにしてしまうと コマンド実行時にバッチファイルの方が 呼ばれてしまうので コマンドとは別の名前を付けましょう。

@ECHO OFF
ECHO ^<pre^>
TREE
ECHO ^</pre^>

ECHO の後ろに出てくる "^"(キャレット)は、 DOS用のエスケープ文字です。

">" や "<" は リダイレクト用の特殊文字なので、 出力する場合は、エスケープしなければなりません。

TREE は フォルダの階層を視覚的に表示してくれるコマンドです。

C:\>TREE         ← 現在のフォルダ以下を出力
C:\>TREE \       ← 現在のドライブ以下を出力
C:\>TREE c:\test ← 指定のフォルダ以下を出力
C:\>TREE /F      ← ファイルも出力

先ほどの「ctree.bat」を実行します。

D:\Photo Files>ctree.bat > tree.html

作成された「tree.html」をWebブラウザで開くと 下のようにフォルダの階層が表示されます。

フォルダ パスの一覧:  ボリューム ローカル ディスク
ボリューム シリアル番号は 00000000 0000:0000 です
D:.
├─会社
├─家族旅行
│  ├─2005年_鳥羽
│  ├─2006年_鳥羽
│  ├─2007年_沖縄
│  └─2008年_北九州
└─プライベート
    ├─友人
    └─??

ただ、これだとフォルダのパスが表示されないので 「ctree.bat」をちょっと改造します。

@ECHO OFF
ECHO %CD%
ECHO.
ECHO ^<pre^>
TREE
ECHO ^</pre^>

%CD% は 現在のフォルダのパスが格納されている変数です。

D:\Photo Files

フォルダ パスの一覧:  ボリューム ローカル ディスク
ボリューム シリアル番号は 00000000 0000:0000 です
D:.
├─会社
├─家族旅行
│  ├─2005年_鳥羽
│  ├─2006年_鳥羽
│  ├─2007年_沖縄
│  └─2008年_北九州
└─プライベート
    ├─友人
    └─??

1行目に、フォルダのパスが表示されるようになりました。

MS-DOSで空行を出力する

意外と知られていない空行の出力です。

通常、メッセージの出力には ECHO コマンドを使用しますが、 このコマンドを引数なしで実行しても空行は出力されません。

C:\> ECHO
ECHO は <ON> です。

C:\> ECHO _ ←全角スペース
ECHO は <ON> です。

C:\> ECHO " "
" "

実は空行を表示するには、 ECHO. と、ピリオドを付けてやります。

C:\> ECHO.

ちなみピリオドを ECHO と離して書くと 普通にピリオドが出力されてしまいますので 注意してください。

C:\> ECHO .
.

MS-DOSのバッチファイルでサブルーチンを使う

DOSバッチファイルは サブルーチンを作ることもできます。

 1: @ECHO OFF
 2: 
 3: CALL :HOGEHOGE 1
 4: CALL :HOGEHOGE 2
 5: CALL :HOGEHOGE 3
 6: 
 7: GOTO :EOF
 8: :HOGEHOGE
 9: ECHO %1

上のバッチファイルを実行すると下のような出力結果になります。

C:\> TEST1.BAT
1
2
3

3〜5行目のCALLで8行目のHOGEHOGEラベルにジャンプします。 CALLは、バッチファイルの最後に来ると、呼び出し元に戻りますので、 3→8→9→4→8→9→5→8→9・・・と処理が移ります。

7行目の:EOFは、最初から設定されているラベルで、ファイルの最後を示しています。 5行目の処理の後に、 8行目に処理が移らないようにしています。

9行目で %1を使用して値を取得していますが、 CALLの呼び出しには引数を指定でき %1,%2・・・と入ってきます。

サブルーチンを複数使うときは、 下のように書きます。

@ECHO OFF

CALL :HOGEHOGE1 1
CALL :HOGEHOGE2 2

GOTO :EOF
:HOGEHOGE1
ECHO %1

GOTO :EOF
:HOGEHOGE2
ECHO %1

ちょっと懐かしい気分にひたる小ネタ

WindowsXPで、偶然見つけた小ネタです。

まず、 「ファイ名を指定して実行」などで 「cmd」と打って DOSプロンプトを起動します。

起動したら、 おもむろに [Alt]+[Enter]を押してください。 DOSプロンプトが全画面表示になります。

「いつもこの画面見てたなぁ…」と 懐かしい気分になりました。

ちなみに、元に戻すときも、[Alt]+[Enter]です。