Programming Field

DOS/Windowsのカレントディレクトリ - DOS コマンド一覧

スポンサーリンク

カレントディレクトリ(Current directory; 現在のディレクトリとも)とは、主にファイル名のパスを省略できるようにするために使用されるディレクトリの情報です。アクセスしたいファイル(またはサブディレクトリ)のあるディレクトリを「カレントディレクトリ」に設定することで、対応するアプリケーションが「カレントディレクトリ」として設定されているディレクトリの中身を確認してファイルを取り扱うという流れが一般的です。

なお、「カレントディレクトリをベースに作業を行う」という意味などから、カレントディレクトリを「作業ディレクトリ」(Working directory)とも呼びます。

※ このページではDOSやWindowsにおけるカレントディレクトリについて説明しています。Unix系システムでもカレントディレクトリは存在し、ここで説明している内容が当てはまる場合もありますが、一部DOS/Windows特有の説明も含んでいますのでご注意ください。

OSから見たカレントディレクトリ

カレントディレクトリの仕組みはOSレベルでサポートされています。実行されるアプリケーションごとに「カレントディレクトリ」の情報が与えられ、APIまたは環境変数を利用してその内容を取得・変更することができます。また、あるアプリケーションが別のアプリケーションを起動させた場合(ここでは起動元を「親プログラム」、起動したプログラムを「子プログラム」と呼びます)、その時点での親プログラムの「カレントディレクトリ」が子プログラムの「カレントディレクトリ」に設定されます。

※ 原則として異なるアプリケーション(アプリケーション空間)のカレントディレクトリを変更することはできません。そのため、子プログラム内でカレントディレクトリを変更しても親プログラムのカレントディレクトリは変更されません。なお、command.comcmd.exeがバッチファイルを実行し、そのバッチファイルがCallによって別のバッチファイルを実行する場合は、子プログラムを起動せず同じアプリケーション空間内でバッチファイルが実行されるため、別バッチファイル内でのカレントディレクトリの変更は元のバッチファイルにも影響を及ぼします。
※ 子プログラムを起動する際、親プログラムは明示的に子プログラムのカレントディレクトリを指定して起動することが可能です。そのケースもあるため、必ずしも子プログラムのカレントディレクトリが親プログラムのカレントディレクトリと一致するとは限りません。

OS内でも一部の機能でカレントディレクトリを使用しているものがあります。例として、Win32APIのCreateProcess関数(子プログラムを起動するほとんどの場合に使用されます)やSearchPath関数(ファイルを探してフルパスを得る場合に使用されます)、および各種ファイル操作関数(CreateFile関数など)では、指定されたファイル名にディレクトリパスが含まれていないときにカレントディレクトリを検索対象・操作対象とすることがあります。

なお、子プログラムの起動以外でファイルやディレクトリを取り扱う場合、カレントディレクトリ内のファイルを用いるかどうかは使用するアプリケーションの実装に依存します。ディレクトリパス名の含まれていないファイルを扱うとカレントディレクトリ内のファイルではなく実行したプログラムの存在するディレクトリ内のファイルを扱う、という実装を行っている可能性もあるため、各アプリケーションの説明を確認してください。なお、特筆が無い場合はOSレベルでのサポートを利用している場合が多いため、ディレクトリパス名の無いファイル名を用いるとカレントディレクトリが使用されると考えられます。

カレントドライブとカレントディレクトリ

DOSやWindowsでは、カレントディレクトリはシステム上に存在するドライブごとに存在します。DOSシステムでは「カレントドライブ」が存在しており、ドライブを含めてカレントディレクトリを変更するにはカレントドライブも変更する必要があります。(INT 21HのAH=0EHで設定、AH=19Hで取得)

Windows(NTシステム)ではネットワークディレクトリなどドライブの存在しないパスも存在するためかカレントドライブは存在せず、ドライブごとのカレントディレクトリとは別にドライブを含めた1つの「カレントディレクトリ」が存在しています。ただしDOSとの互換を考慮し、CランタイムライブラリやVBの関数として「カレントドライブ」の概念を用いているものがあります。これらは「1つのカレントディレクトリ」に対応するドライブを扱うような実装がなされており、以下のような処理が行われています。

なお、Windowsでも「ドライブごとのカレントディレクトリ」が扱えるよう、環境変数として「=X:」という名前の変数(Xはドライブ文字)に対応するドライブのカレントディレクトリを保持しています。

※ Windowsで「カレントドライブのみ」を変更するには、SetCurrentDirectory関数の引数にドライブ文字とコロンのみを含む文字列「X:」を指定します。これにより、「1つのカレントディレクトリ」が指定されたドライブの「(ドライブごとの)カレントディレクトリ」に変更されます。

MS-DOSプロンプトやコマンドプロンプトでは、DOSと同様「カレントドライブ」と「ドライブごとのカレントディレクトリ」を組み合わせて扱うようなシステムを採っています。プロンプト上では「X:」(Xはドライブ文字)を直接入力してカレントドライブを、CdまたはChdirコマンドを使ってドライブごとのカレントディレクトリを変更します。なお、各ドライブ(カレントドライブ含む)に対応するカレントディレクトリの取得はCd(Chdir)を用います。カレントドライブを直接取得する方法はありませんが、オプションを指定しないでCd(Chdir)を呼び出すと、その際に表示されるカレントディレクトリのパス内にカレントドライブが含まれます。

[Windows NT系] カレントディレクトリはSetlocalによる環境のローカル化の影響を受けます。Setlocal実行後にカレントディレクトリを変更してローカル環境を終了(Endlocalまたはバッチファイルを終了)すると、カレントディレクトリはローカル化する前のものに戻ります。

[Windows NT系][拡張構文] 拡張構文が有効(Setlocalもご覧ください)になっているコマンドプロンプトでは、環境変数「%CD%」によりカレントディレクトリの値を使用することができます。他の環境変数と同様の使い方が可能であるため、「%CD:~0,1%」とするとカレントディレクトリのドライブ文字部分(すなわちカレントドライブ)を使うことができます。ただしSetコマンドで「CD」という環境変数に値をセットしても、カレントディレクトリを変更することはできません。

サンプル1

cd MyDocs\Addrs
asearch.exe result.log

カレントディレクトリを「MyDocs\Addrs」に移動し、「asearch.exe result.log」を実行します。プログラム「asearch.exe」は変更したカレントディレクトリ上で実行されるため、そのプログラムがカレントディレクトリ内のデータを扱う場合は「MyDocs\Addrs」以下のデータを扱うことになります。

Cdに渡しているパスは相対パスになっています。そのため、この構文では変更前のカレントディレクトリに「MyDocs\Addrs」というサブディレクトリが存在しないとカレントディレクトリの変更に失敗します。

サンプル2 (バッチファイル)

@echo off

call :enum_all_drives
exit /b 0

:enum_all_drives
    call :enum_drives_iter A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
    exit /b 0

:enum_drives_iter
    if "%1"=="" exit /b 0
    cd %1: >NUL 2>NUL
    if not errorlevel 1 echo %1
    shift
    goto enum_drives_iter

[Windows NT系][拡張構文] 現在のシステムで利用できるドライブ文字を1行ずつに分けて画面に出力します。このバッチファイルでは、Cd(Chdir)コマンドが「指定したドライブのカレントディレクトリ」を出力する機能をアレンジして利用しています。具体的には、Cdでは「cd X:」という実行でドライブが存在するときにカレントディレクトリを出力し、存在しないときにエラーメッセージと0以外の終了コードが返るという処理が行われます。そこで、出力リダイレクト「>」を利用して画面への出力をすべて抑制し、「if errorlevel」で残った終了コードの判定を行うことで、該当のドライブが存在するかどうかの判定を行うことができます。終了コードが0であれば、Ifに続くEchoが実行され、画面(標準出力)にドライブ文字が出力されます。

※ 「echo %1」の部分を変えることで、存在するドライブ(%1にドライブ文字が入ります)すべてに対する処理を実行することができます。また少々遠回りですが、以下のようにこのバッチファイル(enum_drives.batとします)の出力を「for /F」で解析させるという方法も採ることができます(Forコマンドを使うと、ドライブ文字の列挙処理を1つのバッチファイルにまとめて使いまわすことができます)。

for /F "delims=" %D in ('enum_drives.bat') do foo.exe %D