コマンドプロンプトのcdが使いづらいのでなんとかしてみた


コマンドプロンプトの cd コマンドって使いづらいですよね?

Linux で一般的な POSIX シェルの cd とは違い、以下のような欠点があります。

  1. cd だけでホームディレクトリに移動できない。
  2. cd - で前のディレクトリに戻れない。
  3. 環境変数 PWDOLDPWD がない。(これは別に無くてもいいけど)
  4. ドライブの移動には /D オプションを使用する必要がある。

そこでバッチファイルで cd コマンドのラッパーを作ってなんとかしてみました。

shcd.bat
@echo off

if "%OLDPWD%" == "" set OLDPWD=%USERPROFILE%
if "%PWD%" == "" (
  for /F "usebackq tokens=*" %%d in (`cd`) do set PWD=%%d
)

if "%~1" == "-" if '%1' == '-' goto :BACK

:GO
  setlocal
  for /F "usebackq tokens=*" %%d in (`cd`) do set OLDPWD=%%d

  if "%~1" == "" (
    cd /D %USERPROFILE%
  ) else (
    cd /D %*
  )
  if errorlevel 1 exit /B %ERRORLEVEL%

  for /F "usebackq tokens=*" %%d in (`cd`) do set PWD=%%d
  endlocal & cd /D %PWD% & set PWD=%PWD% & set OLDPWD=%OLDPWD%
  goto :EOF

:BACK
  setlocal
  cd /D %OLDPWD%
  if errorlevel 1 exit /B %ERRORLEVEL%
  endlocal & cd /D %OLDPWD% & set PWD=%OLDPWD% & set OLDPWD=%PWD%

このバッチファイルをどこかにおいて、doskey でエイリアス設定をすれば完成です。潰してしまった cd コマンドのカレントディレクトリを表示する機能の代わりとして pwd も用意しています。

doskey cd=shcd.bat $*
doskey pwd=cd

doskey のエイリアス設定はコマンドプロンプト起動時にバッチファイルを自動実行させると便利です。(参考 コマンドプロンプトの開始時に定型処理を自動実行するには

以上です。

おまけ

これだけではなんなんで、少しコードの分かりづらい場所の解説を。

for /F "usebackq tokens=*" %%d in (`cd`) do set PWD=%%d

現在のディレクトリ(= cd コマンドの出力結果)を環境変数 PWD に入れるコードです。なんと冗長なのでしょうか・・・

if "%~1" == "-" if '%1' == '-' goto :BACK

cd - は前のディレクトリに戻るが、cd "-" だとディレクトリ名として扱うようにした(つもり。バグがあるかも)

:GO
  setlocal
  for /F "usebackq tokens=*" %%d in (`cd`) do set OLDPWD=%%d
 略
  endlocal & cd /D %PWD% & set PWD=%PWD% & set OLDPWD=%OLDPWD%

環境変数 OLDPWD を変更していますが、途中のディレクトリ移動でエラーになったときに途中で exit し、なかったことにするために setlocal を使用しています。ディレクトリ移動できた場合のみ endlocal を実行しますが、通常はこれで環境変数の変更(とディレクトリ移動)が元に戻るのですが、同じ行にコードを書くことで endlocal の外に環境変数を持ち出すことができます。(行の解釈と実行の順番からこのような挙動になるそうです。)

:BACK
 略
  endlocal & cd /D %OLDPWD% & set PWD=%OLDPWD% & set OLDPWD=%PWD%

ここも似ていますが、ワーク変数を用いること無く二つの変数の中身を入れ替えています。

あとグチですが、バッチファイルはダブルクォートの扱いが面倒ですね。本来の cd の挙動と同じく、引数をダブルクォートで括っても括らなくても問題なく、またスペースが含まれてるディレクトリであってもちゃんと動くようにしたつもりですが、ちょっとした書き方の違いで変数の中にダブルクォートが含まれたりして大変でした・・・。