Search code examples
batch-filecmd

Why can FOR not find a specified file when used to read all lines from within my batch script?


I have a few log files that my batch script needs to be able to read and parse.

I've run into a bit of a problem, where my FOR loop can read most files, but cannot read a specific one. If I run in a command prompt window

for /f %Z in (N151204.log) do echo %Z

it works great, but exactly the same syntax on a different file:

for /f %Z in (IN151205.log) do echo %Z

Gives me:

The system cannot find the file IN151205.log.

I can read file IN151205.log with

more IN151205.log

without a problem. So it doesn't seem to be a permissions issue, or read-locked as far as I can tell.

Why is the for loop having issues with this particular file?


Solution

  • The error message of command FOR is caused by the fact that FOR command opens a file for reading always using CreateFile with FILE_SHARE_READ AND FILE_SHARE_DELETE.

    The log file IN151205.log is obviously written at the moment by another application with having a write lock established on the file. The file access by command FOR fails therefore with a sharing violation because of FILE_SHARE_DELETE.

    MORE has success to open the file with write lock set and outputs the lines as it really only reads the file and using a different method. MORE uses CreateFileMapping using PAGE_READWRITE to read and output the file contents page wise which works completely different than CreateFile and can be used also on files currently locked by another application as mentioned in Remarks section with:

    It is not required, but it is recommended that files you intend to map be opened for exclusive access.

    PAGE_READWRITE allows also read access on a file currently allowing only read access according to sharing mode.

    See also the Microsoft documentations Generic Access Rights and File Security and Access Rights.

    The error message output by FOR on access to a file fails because of a sharing violation is obviously not good as being misleading for users.

    EDIT:

    Reading a write-locked file from within a batch file line by line with ignoring empty lines can be done with

    for /F delims^=^ eol^= %%I in ('more IN151205.log') do echo(%%I
    

    and with

    for /F delims^=^ eol^= %%I in ('type IN151205.log') do echo(%%I
    

    Thanks Aacini and Squashman for this additional information.