@echo off
setlocal ENABLEDELAYEDEXPANSION
set ret=0
set targetdir=invalid
set myname=cmdmark
set datafile=%~dp0%myname%_list.txt
set indent_list=
set indent_indicator=
if "%1"=="help" (
echo [Usage]
echo %~n0 : List all bookmarks.
echo %~n0 add : Add the current directory as bookmark.
echo %~n0 edit : Open the bookmark datafile with your editor.
echo %~n0 check : Check pathes in the datafile and alert if an error exists.
echo %~n0 ^(NUMBER^) : Goes ^(pushd^) to the directory matched the number.
echo %~n0 ^(QUERY^) : Goes ^(pushd^) to the directory matched the query.
exit /b
)
if exist %datafile% (
rem Do Nothing.
) else (
echo The datafile "%datafile%" do not exists, create firstly.
copy nul %datafile%
)
if "%1"=="check" (
set /a cnt=0
set /a error_cnt=0
for /F "usebackq tokens=*" %%i in (`type %datafile%`) do (
set /a cnt=!cnt!+1
if exist %%i (
rem Do Nothing.
) else (
set /a error_cnt=!error_cnt!+1
echo %indent_list%!cnt!: %%i
)
)
echo.
echo %indent_indicator%!error_cnt! invalid directories.
exit /b
)
if "%1"=="edit" (
start "" %datafile%
exit /b
)
if "%1"=="add" (
echo %cd% >> %datafile%
echo Add "%cd%" as bookmark.
exit /b
)
if "%1"=="" (
call :print_bookmarks
exit /b
)
call :is_numeric %1
if %ret% neq 0 (
set targetnum=%1
set /a cnt=0
for /F "usebackq tokens=*" %%i in (`type %datafile%`) do (
set /a cnt=!cnt!+1
if "!cnt!"=="!targetnum!" (
endlocal
call :do_pushd %%i
exit /b
)
)
echo Not found: !targetnum!
exit /b
)
rem Matching...
set /a cnt=0
for /F "usebackq tokens=*" %%i in (`type %datafile% ^| findstr /I %1`) do (
set /a cnt=!cnt!+1
)
set matched_count=!cnt!
if %matched_count% equ 1 (
for /F "usebackq tokens=*" %%i in (`type %datafile% ^| findstr /I %1`) do (
endlocal
call :do_pushd %%i
)
exit /b
)
if %matched_count% equ 0 (
echo Not Found: %1
exit /b
)
echo Multiple matched... Please consider your query.
set /a cnt=0
for /F "usebackq tokens=*" %%i in (`type %datafile%`) do (
set /a cnt=!cnt!+1
echo %indent_list%!cnt!: %%i | findstr /I %1
)
exit /b
rem ============================
rem ======== subrootins ========
rem ============================
rem You must call endlocal from the main rootin.
rem to work pushd command correctly.
:do_pushd
echo pushd %*
pushd %*
exit /b
:print_bookmarks
set /a cnt=0
for /F "usebackq tokens=*" %%i in (`type %datafile%`) do (
set /a cnt=!cnt!+1
echo %indent_list%!cnt!: %%i
)
echo.
echo %indent_indicator%!cnt! bookmarks.
exit /b
rem @retval 0 If it is not numeric.
:is_numeric
set "var="&for /f "delims=0123456789" %%i in ("%1") do set var=%%i
if defined var (set ret=0) else (set ret=1)
exit /b
これは何してる?
これは Windowsのバッチ(cmd)で作った「ディレクトリのブックマーク管理ツール」です。
カレントディレクトリを「しおり」としてテキストファイルに保存しておき、番号や検索語でそのフォルダへ pushd で移動できるようにしています。
%~dp0%myname%_list.txt
%~dp0 = このバッチがあるフォルダmyname=cmdmark なので、cmdmark_list.txt という名前になります。ファイルが無ければ copy nul %datafile% で空ファイルを作ります。
help使い方を表示して終了。
call :print_bookmarks で、ブックマーク一覧を番号付きで表示します。
例:
` 1: C:\work
2: D:\proj`
最後に X bookmarks. と総数も表示。
add現在のディレクトリ(%cd%)をデータファイル末尾に追記してブックマーク登録。
echo %cd% >> %datafile%
editブックマークファイルを start "" %datafile% で開きます(関連付けされたエディタ等で開く)。
checkファイルの各行が「実在するパスか」を if exist でチェックし、存在しないものを番号付きで列挙します。
最後に「invalid directories の数」を出します。
3)call :is_numeric %1 で数字か判定し、数字なら「その番号の行」を探します。
一致した行が見つかったら :do_pushd を呼んでそのディレクトリへ移動します。
※途中で endlocal してから pushd しているのは、setlocal の影響を抜けて pushd が呼び出し元のシェル(元のcmd)に効くようにするための工夫です。
proj)findstr /I %1 で大文字小文字無視で部分一致検索します。
pushdNot Found: ...:do_pushdpushd %* を実行(移動するだけ):print_bookmarks:is_numericret=1、数字以外が混じるなら ret=0 を返す判定要するに「よく行くフォルダを登録して、番号やキーワードで素早く移動する」ためのバッチです。必要なら、削除機能や重複登録防止なども追加できます。
これつくったエンジニアは優秀?
このバッチを書いた人は、少なくとも cmd/batch の癖を理解して実用ツールにまとめる力はあるので、一定以上には優秀だと思います。ただし「洗練されているか」「堅牢か」は別で、改善余地もはっきりあります。
pushd を「このバッチの中だけ」ではなく 呼び出し元の cmd に効かせるために、該当箇所で endlocal してから call :do_pushd しているのは、初心者だとまず気づきません。add/edit/check/list/番号/検索 というサブコマンド設計は分かりやすく、現場の“自分用ツール”としては実戦的。findstr と標準機能だけで実現しているのは、配布・運用面で強いです。if exist %datafile% や type %datafile% が未クォートなので、パスにスペースがあると壊れます。if exist %%i も、ブックマーク先に & や ( ) などが入ると危険。findstr /I %1 は検索語に \ や * などが入ると意図通りにならないことがある(正規表現扱い)。findstr /I /C:"%~1" みたいに固定文字列検索寄りにしたい。add が無条件追記なので同じパスが増殖します。type で読んでるので空行も番号に混ざり得ます。if exist はファイル/フォルダ両方に反応する必要なら、このコードから「スペース対応」「重複排除」「削除機能」「正確な検索」まで含めた改善案も具体的に出せます。