How to check in command-line if a given file or directory is locked (used by any process)?

Not sure about locked directories (does Windows have that?)

But detecting if a file is being written to by another process is not difficult.

@echo off
2>nul (
  >>test.txt echo off
) && (echo file is not locked) || (echo file is locked)

I use the following test script from another window to place a lock on the file.

(
  >&2 pause
) >> test.txt

When I run the 2nd script from one window and then run the 1st script from a second window, I get my “locked” message. Once I press <Enter> in the 1st window, I get the “unlocked” message if I rerun the 1st script.

Explanation

Whenever the output of a command is redirected to a file, the file of course must be opened for write access. The Windows CMD session will attempt to open the file, even if the command does not produce any output.

The >> redirection operator opens the file in append mode.

So >>test.txt echo off will attempt to open the file, it writes nothing to the file (assuming echo is already off), and then it closes the file. The file is not modified in any way.

Most processes lock a file whenever they open a file for write access. (There are OS system calls that allow opening a file for writing in a shared mode, but that is not the default). So if another process already has “test.txt” locked for writing, then the redirection will fail with the following error message sent to stderr – “The process cannot access the file because it is being used by another process.”. Also an error code will be generated upon redirection failure. If the command and the redirection succeed, then a success code is returned.

Simply adding 2>nul to the command will not prevent the error message because it redirects the error output for the command, not the redirection. That is why I enclose the command in parentheses and then redirect the error output to nul outside of the parens.

So the error message is effectively hidden, but the error code is still propagated outside of the parens. The standard Windows && and || operators are used to detect whether the command inside the parens was successful or failed. Presumably echo off will never fail, so the only possible reason for failure would be the redirection failed. Most likely it fails because of a locking issue, though technically there could be other reasons for failure.

It is a curious “feature” that Windows does not set the %ERRORLEVEL% dynamic variable to an error upon redirection failure unless the || operator is used. (See File redirection in Windows and %errorlevel%). So the || operator must read the returned error code at some low level, not via the %ERRORLEVEL% variable.

Using these techniques to detect redirection failure can be very useful in a batch context. It can be used to establish locks that allow serialization of multiple events in parallel processes. For example, it can enable multiple processes to safely write to the same log file at the “same” time. How do you have shared log files under Windows?


EDIT

Regarding locked folders. I’m not sure how Windows implements this, perhaps with a lock. But if a process has an active directory involving the folder, then the folder cannot be renamed. That can easily be detected using

2>nul ren folderName folderName && echo Folder is NOT locked || echo folder is LOCKED

EDIT

I have since learned that (call ) (with a space) is a very fast command without side effects that is guaranteed to succeed with ERRORLEVEL set to 0. And (call) (without a space) is a fast command without side effects that is guaranteed to fail with ERRORLEVEL 1.

So I now use the following to check if a file is locked:

2>nul (
  >>test.txt (call )
) && (echo file is not locked) || (echo file is locked)

Leave a Comment