2

I am trying to iterate files in a folder and process them with another batch file inside the do loop. It works with echo but as soon as I use the variable as input to the program, it echoes the () part and everything inside.

Here's what I'm trying to do.

@echo off
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
for /r %%f in (/folder/*) do (
  set name="%%~nf"
  echo !name! <--- ok
  process.bat !name! <--- echoes () and commands inside this do loop
)
ENDLOCAL

The process.bat just capitalizes the first letter of the filename and echoes it for debug or confirmation.

ruzip
  • 35
  • 5
  • 1
    Explanation for why the looped commands are ECHOed here: https://stackoverflow.com/a/12082732/1012053 – dbenham Sep 02 '19 at 12:48

1 Answers1

0

A batch file must be called from within a batch file using command call as otherwise Windows command processor continues processing on other batch file with never returning back to initial batch file.
See also: How to call a batch file that is one level up from the current directory?

Please read excellent answer on batch file echo on/off not working properly written by dbenham for the reason on getting suddenly the commands executed by FOR output after first execution of process.bat without using command CALL. I cannot explain better what happens in this case.


The directory separator on Windows is the backslash character \ and not the forward slash / as on Linux or Mac. Windows supports also / in file/folder paths for compatibility reasons by automatically replacing all / by \ before accessing the Windows file systems, but a good written script uses 100% correct syntax and does not depend on automatic corrections done by other programs. / is used on Windows mainly for command line switches.

The usage of / instead of \ can result in an unexpected behavior. For example run a batch file with following content:

@echo off
echo Files in directory %SystemRoot:\=/%/:
for %%I in (%SystemRoot:\=/%/*) echo %%I
echo/
pause
echo/
echo Files in directory %SystemRoot%\:
for %%I in (%SystemRoot%\*) echo %%I
echo/
pause

The first FOR using C:/Windows/* as wildcard pattern outputs the file names with just drive letter + colon + file name + file extension. The file path \Windows\ is missing in output file names. The second FOR loop using C:\Windows\* as wildcard pattern outputs the full qualified file names, i.e. drive letter + colon + file path + file name + file extension.


A file/folder path starting with \ references a directory or file relative to root directory of current DRIVE. This is explained by the Microsoft documentation Naming Files, Paths, and Namespaces.

It looks like folder is a subdirectory in directory of the executed batch file. In this case / or \ at beginning of folder path is definitely not correct. The backslash at beginning can be omitted or .\ is used to reference the directory folder in current directory on execution of the batch file. But the current directory on batch file execution can be also different to directory containing the executed batch file, for example on running the batch file as administrator, or on running the batch file as scheduled task, or on running the batch file from a network resource accessed using a UNC path. For that reason it is advisable to reference explicitly subdirectory folder in directory of the batch file.


Delayed environment variable expansion is not needed as long as the file name assigned currently to the loop variable does not need to be modified other than the modifiers of for support it. A command line like set name="%%~nf" does not work correct with enabled delayed expansion and file name contains one or more ! because of cmd.exe interprets the exclamation mark(s) in file name as beginning/end of a delayed expanded environment variable reference.
See also: How does the Windows Command Interpreter (CMD.EXE) parse scripts?


It looks like a recursive search for non-hidden files is not really needed as otherwise passing just file name without path and file extension would be not enough to get the right file processed by other batch file process.bat.


So the entire task can be done most likely also with:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for %%I in ("%~dp0folder\*") do call "%~dp0process.bat" "%%~nI"
endlocal

But if the other batch file process.bat expects that the passed file name without file extension and path is in current directory on execution of process.bat, it is necessary to make the subdirectory folder in directory of this batch file first the current directory.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
pushd "%~dp0folder"
for %%I in (*) do call "%~dp0process.bat" "%%~nI"
popd
endlocal

Note: The batch file folder path referenced with %~dp0 always ends with a backslash. Therefore no additional backslash should be used on concatenating this path string with a file/folder name to avoid having finally on execution of the batch file \\ in full qualified file/folder name, although Windows kernel corrects such paths also automatically by removing second backslash in this case.

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

  • call /?
  • echo /?
  • endlocal /?
  • popd /?
  • pushd /?
  • set /?
  • setlocal /?
Mofi
  • 38,783
  • 14
  • 62
  • 115