「CD コマンドの機能拡張 第二版」以来、16年ぶりの大幅修正。機能は変えていないが、リファクタリングで機能追加がシンプルになった。
cdd.bat
という名前で作って、doskey cd=cdd $*
でaliasを定義して使う。
機能は、
- 移動はすべて pushd で行う。
- cd のみのときはディレクトリスタックの表示
- ホーム(%HOME%)への移動は cd ~
- cd - で前のディレクトリに戻る
- cd + で現ディレクトリと一つ前のディレクトリの交換
- cd 存在するディレクトリ だとそこへ移動
- cd ショートカット の場合、ショートカット先がディレクトリならそこへ移動し、ファイルだとそのファイルのあるディレクトリへ移動
- cd 存在するファイル だとそのファイルのあるディレクトリへ移動 (explorerからcmdプロンプトへファイルをドラッグ&ドロップしたとき便利)
- cd それ以外 の場合環境変数CDPATHを探索してオペラランドがそこにディレクトリとして存在すればそこに移動
ほとんどの機能はモジュール化していて、ファイルの最後で定義する。
指定文字列 移動先ディレクトリ
指定文字列 サブルーチン
サブルーチンの1つとして、RubyのGemsディレクトリへの移動を書いてみた。
Firefoxのプロファイルディレクトリも、profiles.ini
を読んで決めるようにしようかと思ったけど、面倒くさいわりにメリットが無いのでやめた。
@echo off rem 定義済みの移動先ならそこに移動する call :PreDefined "%~dpnx0" "%~1" if not ERRORLEVEL 1 exit /b rem 存在するディレクトリ、ファイル、ショートカットか? rem ファイルの場合はそのディレクトリに移動する if exist "%~1" ( dir /b/ad "%~1" >NUL 2>NUL if not ERRORLEVEL 1 ( call :Pushd "%~1" ) else ( if /i "%~x1"==".lnk" ( call :Shortcut "%~1" if not ERRORLEVEL 1 exit /b ) call :Pushd "%~dp1" ) exit /b ) rem %CDPATH% に存在するディレクトリなら、そこに移動する if not "%~$CDPATH:1"=="" dir /b/ad "%~$CDPATH:1" >NUL 2>NUL && ( call :Pushd %~$CDPATH:1 exit /b ) :Pushd rem 移動用処理 rem pushd が成功しても元と同じならpopdする(同じ履歴を残さないため) for /f "delims=" %%X in ("%CD%") do ( pushd %* if not ERRORLEVEL 1 for /f "delims=" %%Y in ('echo "%%CD%%"') do ( if "%%X"=="%%~Y" popd ) ) exit /b :Shortcut rem ショートカットファイルのリンク先を調べてそこに移動する setlocal enabledelayedexpansion set "SV=" set "FILE=" for /f "delims=" %%A in ('more ^< "%~1"') do ( set A=%%A if "!A:~1,2!"==":\" for %%B in (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) do if "!A:~0,1!"=="%%B" set "FILE=%%A" if defined SV (if defined FILE (set "FILE=!FILE!%%A")else set "FILE=!SV!\%%A")&set "SV=" if "!A:~0,2!"=="\\" set "SV=%%A" ) if defined FILE endlocal&call :Pushd "%FILE%"&exit /b 0 rem リンク先が見つからない場合 exit /b 1 :PreDefined rem 定義済み移動先の処理を行う rem 移動先ディレクトリ名 または 呼び出すサブルーチン名 setlocal enabledelayedexpansion set "DATA=" for /f "usebackq tokens=1*" %%A in (%1) do ( if /i "%%~A" == "__DATA__" ( set DATA=1 ) else if defined DATA ( set "X=%%~B" if /i "%%~A" == "%~2" if "!X:~0,1!" == ":" ( endlocal call %%~B %* exit /b 0 ) else ( endlocal call :Pushd "%%~B" exit /b 0 ) if /i "%~2" == ":Help" echo.%%A %%B ) ) if /i "%~2" == ":Help" exit /b 0 rem 定義済み移動先に存在しなかった exit /b 1 rem ここから個別処理 :Dirs rem ディレクトリスタックを横に並べて表示する setlocal enabledelayedexpansion set TEMPFILE="%TEMP:"=%\cd$$.tmp" pushd > %TEMPFILE% set "DIRS=%CD%" for /f "usebackq delims=" %%A in (%TEMPFILE%) do set "DIRS=!DIRS! %%~A" del %TEMPFILE% 2>NUL set /p "=%DIRS%"<NUL exit /b :Back rem 1つ前のディレクトリへ popd goto :Dirs :Swap rem 1つ前のディレクトリに移動して、履歴に今のディレクトリを入れる for /f "delims=" %%X in ('echo "%%CD%%"') do ( popd for /f "delims=" %%Y in ('echo "%%CD%%"') do ( popd for /f "delims=" %%Z in ('echo "%%CD%%"') do ( if not "%%~Y"=="%%~Z" (pushd %%X) else (cd /d %%X) if not "%%~X"=="%%~Y" pushd %%Y ))) goto :Dirs :Help rem 定義済み移動先の一覧の表示 call :PreDefined %1 :Help exit /b :RubyGems rem RubyGemsのディレクトリへ for /f "tokens=1-3 delims=." %%A in ('ruby -e "puts RUBY_VERSION"') do ( call :Pushd "D:\Ruby\lib\ruby\gems\%%A.%%B.0\gems" ) exit /b rem ここから移動先定義 __DATA__ "" :Dirs - :Back + :Swap /? :Help ~ %HOME% / %TEMP% // D:\Temp /e %windir%\system32\drivers\etc /f %APPDATA%\Mozilla\Firefox\Profiles\xxxxxxxx.20180101 /g :RubyGems