これは何
Windows のバッチファイルで、ファイルのタイムスタンプを更新する方法を紹介します。
- できること
- 空ファイルの作成
- ファイルのタイムスタンプ更新
- できないこと
- オプションを使うこと。タイムスタンプを指定時刻に変更したりできません
- ディレクトリのタイムスタンプを更新すること
- 多分できないこと
- ネットワークパスのファイルに対する touch 操作。試せてないのでわかりません。誰か、成功したら教えて
想定読者
WSL 、 cygwin 、 msys2 を Windows に install したくない人
外部ツールにできるだけ依存したくない人
結論
@echo off
if "%~1"=="" exit /b 0
if "\\.\"=="%~dp1" exit /b 0
pushd "%~dp1"
if not exist "%~nx1" (
copy nul "%~nx1">nul
) else if not exist "%~nx1\" (
copy /B /Y "%~nx1"+>nul
)
if errorlevel 1 (
popd
exit /b %errorlevel%
)
popd
exit /b 0
実行例
正しい使い方
通常のファイルに対する touch 操作は、成功すると 0 が返ります。
アクセス権限等で失敗すると非0が返ります。
通常のファイルに対する touch
C:\a>dir
2019/10/12 00:27 <DIR> .
2019/10/12 00:27 <DIR> ..
C:\a>touch.bat foo.txt
C:\a>echo %errorlevel%
0
C:\a>dir
2019/10/12 00:27 <DIR> .
2019/10/12 00:27 <DIR> ..
2019/10/12 00:27 0 foo.txt
C:\a>touch.bat foo.txt
C:\a>echo %errorlevel%
0
C:\a>dir
2019/10/12 00:27 <DIR> .
2019/10/12 00:27 <DIR> ..
2019/10/12 00:30 0 foo.txt
読み取り専用ファイルに対する touch
読み取り専用属性を付与した foo.txt に対する touch
C:\a>touch.bat foo.txt
アクセスが拒否されました。
C:\a>echo %errorlevel%
1
正しくない使い方
特殊ファイルやディレクトリ等、 touch.bat が対応していないファイルに対する touch は 0 が返ります。
特殊ファイルに対する touch
C:\a>touch.bat nul
C:\a>echo %errorlevel%
0
ディレクトリに対する touch
C:\a>mkdir bar
C:\a>touch.bat bar
C:\a>echo %errorlevel%
0
雑談
バッチファイルの変数展開は、文を評価するタイミング展開されてしまうので、 if 文や for 文の中で変数を更新しようとすると、色々と面倒臭くて嫌いだった。しかし、touch.bat
を作成していて、初めて便利だと思った。
それは、copy
が失敗したときの復帰処理が書きやすかったことです。
復帰処理は、copy
の戻り値を呼び出し元に転送しつつ、popd
を実行して元のディレクトリに戻る必要があります。つまり、copy
の戻り値を exit /b
の引数に渡しつつ、popd
の実行をすることになります。if文の中で popd
と exit /b %errorlevel%
を実行すると、if文を評価するタイミングで %errorlevel%
が評価されるので、exit /b
の引数に指定した %errorlevel%
は popd
の英共を受けません。その結果、中間変数に %errorlevel%
の値を保持する必要はなくなります。素晴らしい。
バッチファイルで一時変数を使う場合、 setlocal
しないと環境変数が汚れるので、できるだけ使いたくありません。その点でも良いと思いました。
参考リンク
【Windows】空のファイルを作成する(Linuxで言うtouch)
Windows OSでファイルの最終変更時刻を更新する(touchコマンドを実現する)
batファイルでコマンドの実行結果を出力しないようにする方法
How to test if a path is a file or directory in Windows batch file?