Following batch script is supposed to loop through files in specified directory. The directory contains files with two extensions which are .in
and .out
. For example, there is a dog.in
file and a dog.out
file. There are multiple such file pairs in that directory. Each file contains only 3-4 lines of text.
Then there is some Java program, which is supposed to get a single .out
file as an input argument, and a single .in
file redirected to stdin
using <
in Java execution command.
The batch script works fine if it only performs a single Java execution for a single pair of files like this:
@ECHO OFF
cd e:\WORK\NetBeansProjects\potyczki
pwd
set infname=D:\___Potyczki_Algorytmiczne\2024\mro_tests\mro1k.in
set outfname=D:\___Potyczki_Algorytmiczne\2024\mro_tests\mro1k.out
java -classpath target/classes/ pl.kazanik.potyczki._2024.Mrowki %outfname% < %infname%
When the batch script is changed to loop through files in a directory and executes the Java program for each pair of files in a loop, then an error is thrown with showing the error message: The system cannot find the file specified.
The error occurs in the batch script, before the Java program execution starts. I know this because as a first line in main
method of the Java program I have a print
message which is not present in the output when the batch file is executed. There is only above error message printed for each file pair in the directory, i.e. for each iteration of the for
loop.
@echo off
setlocal
cd e:\WORK\NetBeansProjects\potyczki
pwd
set testdir=D:\___Potyczki_Algorytmiczne\2024\mro_tests
for %%f in (%testdir%\*.in) do (
set inname=%%f
call set outname=%%inname:in=out%%
call java -classpath target/classes/ pl.kazanik.potyczki._2024.Mrowki %%outname%% < %%inname%%
)
I will be grateful for telling what I am doing wrong in the batch script.
The solution for the single file pair can be enhanced for processing all *.in
files in the specified directory with the following batch file:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
cd /D "E:\WORK\NetBeansProjects\potyczki" || exit /B
if exist java.exe (for %%I in (java.exe) do set "JavaExe=%%~fI") else for %%I in (java.exe) do set "JavaExe=%%~$PATH:I"
if defined JavaExe for %%I in ("D:\___Potyczki_Algorytmiczne\2024\mro_tests\*.in") do "%JavaExe%" -classpath target\classes\ pl.kazanik.potyczki._2024.Mrowki "%%~dpnI.out" <"%%I"
endlocal
The first two command lines define the execution environment with:
The batch file works also with *.in
files containing one or more !
in file name because of disabled delayed variable expansion. The processing of the batch file is also faster because of disabled delayed variable expansion.
The third line changes the current working directory to the specified directory. If that fails because of that directory does not exist anymore or is currently not available on being a network drive, the batch file processing is exited without doing anything.
Java executable is run perhaps thousands of times on thousands *.in
files in the specified directory. It is inefficient to let cmd.exe
search for a file with name java
with a file extension as defined in the local environment variable PATHEXT
in the current working directory and when not found here in the directories of the local environment variable PATH
again and again on each *.in
file to process. The fifth line defines for that reason the environment variable JavaExe
with its fully qualified file name on existing in the current directory E:\WORK\NetBeansProjects\potyczki
or on being found in any directory of the local environment variable PATH
.
If java.exe
could be found somewhere, Java is executed with its fully qualified file name in a simple FOR loop searching in the specified directory D:\___Potyczki_Algorytmiczne\2024\mro_tests
for non-hidden files with the file extension .in
for processing each found *.in
file. The Windows Command Processor does not need to search anymore for this executable repeatedly in file system because of using the absolute file name of java.exe
.
The file name of a *.in
file is assigned to the loop variable I
with full path because of a full path was also used in the wildcard pattern. %%~dpnI.out
references the drive, path and name of the current *.in
input file with the file extension changed to .out
. %%I
references the absolute file name of the current *.in
file.
It would be useful in my opinion that the Java application would also support a command line parameter like "D:\___Potyczki_Algorytmiczne\2024\mro_tests\*.in"
in which case the Java application would search itself in the directory for files matched by the wildcard pattern *.in
and processes every input file with creation of the output file. In other words, the loop is inside the Java application instead of using a batch file for processing multiple input files. That would be even more efficient and is quite easy to code in Java.
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
cd /?
echo /?
endlocal /?
exit /?
for /?
if /?
set /?
setlocal /?
See also single line with multiple commands using Windows batch file for an explanation of the conditional command operator ||
.