You can use for /f
to split the file name into two tokens at the _
delimiter. You don't want to include the .txt
extension, so you need to split %%~nA
instead of %%A
.
You could use dir
with findstr
to verify that the file name has valid format, and change the outer for
loop to for /f
to process that result. For example, you don't want to process a file name that looks like "vendor_.txt"
. My findstr
command verifies there is only one _
and there is at least one non-underscore character both before and after.
One would think that the following would work
@echo off
:: This does not work - each line of input to java has an unwanted trailing space
for /f "delims=" %%A in (
'dir /a-d /b *_*.txt ^| findstr /i "^[^_][^_]*_[^_][^_]*\.txt$"'
) do for /f "delims=_ tokens=1*" %%B in ("%%~nA") do (
echo %%A
echo %%B
echo %%C
) | java -jar c:\generator.jar
But there is an insidious problem due to the fact that each side of the pipe is executed in a new cmd.exe process. Each side of the pipe must be parsed and packaged up into a cmd /c ....
command. The left side ends up looking something like:
C:\Windows\system32\cmd.exe /S /D /C"echo fileName &echo vendor &echo model "
,
with an unwanted space at the end of each line. Adding parentheses like (echo %%A)
does not help.
There is another potential problem if any of the file names contain a poison character like &
. If your vendor name is "Bell&Howell", then the left side process would attempt to execute
echo Bell&Howell
. The "Bell" would echo properly, but the "Howell" would be interpreted as a command and would almost surely fail with an error, but in any case would not give the desired result.
See Why does delayed expansion fail when inside a piped block of code? for more information about potential issues with pipes, along with strategies for dealing with them.
Below is an enhancement to my original code that should fix the problems. I solve the poison character issue by putting the string literals within quotes, and then use a for
statement that executes within the child cmd.exe process to safely strip the quotes before ECHOing the value.
I solve the unwanted trailing space issue by delaying parsing of the command by using an %%echoX%%
"macro". The double percents delays expansion of the "macro" until after we are in the child process.
@echo off
setlocal disableDelayedExpansion
:: This echoX "macro" delays parsing of the echo command to avoid the unwanted trailing space
set "echoX=(echo %%~X)"
for /f "delims=" %%A in (
'dir /a-d /b *_*.txt ^| findstr /i "^[^_][^_]*_[^_][^_]*\.txt$"'
) do for /f "delims=_" tokens=1*" %%B in ("%%~nA") do (
(for %%X in ("%%~A" "%%B" "%%C") do @%%echoX%%) | java -jar c:\generator.jar
)
Another option is to define a multi-line variable with embedded linefeeds, and then use CMD /V:ON to enable delayed expansion in the child process.
@echo off
setlocal disableDelayedExpansion
for %%L in (^"^
%= This creates a quoted linefeed character in the FOR variable L =%
^") do for /f "delims=" %%A in (
'dir /a-d /b *_*.txt ^| findstr /i "^[^_][^_]*_[^_][^_]*\.txt$"'
) do for /f "delims=_" tokens=1*" %%B in ("%%~nA") do (
set "str=%%A%%~L%%B%%~L%%C"
cmd /v:on /c "(echo !str!)" | java -jar c:\generator.jar
)
Here is a simpler alternative that uses a temporary file instead of a pipe. It avoids the many issues that can arise with pipes.
@echo off
for /f "delims=" %%A in (
'dir /a-d /b *_*.txt ^| findstr /i "^[^_][^_]*_[^_][^_]*\.txt$"'
) do for /f "delims=_" tokens=1*" %%B in ("%%~nA") do (
>temp.txt (
(echo %%~A)
(echo %%B)
(echo %%C)
)
<temp.txt java -jar c:\generator.jar
del temp.txt
)