-1

I run a batch file in the Windows command prompt, and the echo results seem right. But when I process data next, the result shows one of the files does not exist, however, it echoes fine previously.

Also, after running the batch, I tried to echo variables set in the batch before, all failed. I'm wondering why, whether I set variables successfully.

setlocal ENABLEDELAYEDEXPANSION
for /f %%f in ('dir /ad /b ') do (
    echo %%f
    pause
    pushd %%f
    for /d "tokens=1,2 delims=:" %%a in ('dir /b *.a*.dat in %%f' ) do (
        set COM_DATA=%%a
        echo !COM_DATA!
        set COM_V=%%f\com-v.dat
        echo !COM_V!
        set COM_M=%%f\com-M.dat
        echo !COM_M!
     ::some data process
    )
    chdir
    popd
)
endlocal

I expect I can echo all variables.

  • 1
    What do you mean all failed? Provide details. To echo a variable in DOS you use: `echo %VARIABLE%`. – lurker Apr 25 '19 at 02:29
  • 3
    Type `endlocal /?`. – Noodles Apr 25 '19 at 02:41
  • 1
    If you have an issue with the data process, why omit that portion of your nested loop? Please could you [edit your question](https://stackoverflow.com/posts/55840899/edit) to include that missing code. In the meantime you should open a Command Prompt window, enter `For /?` and `Dir /?`, read the output from each and make corrections as necessary. – Compo Apr 25 '19 at 05:18
  • Don't use `::`-style comments in code blocks, they may lead to unexpected behaviour! use `rem` instead... – aschipfl Apr 25 '19 at 08:38

2 Answers2

1

There are lots of mistakes. I recommend opening a command prompt window, run for /? and read the output help/documentation for command FOR. See also Microsoft's documentation for Windows Commands and even better SS64.com - A-Z index of the Windows CMD command line.

@echo off
setlocal EnableExtensions EnableDelayedExpansion
for /D %%I in (*) do (
    echo Processing directory "%%~fI" ...
    pushd "%%I"
    for %%J in (*.a*.dat) do (
        set "COM_DATA=%%J"
        echo !COM_DATA!
        set "COM_V=%%I\com-v.dat"
        echo !COM_V!
        set "COM_M=%%I\com-M.dat"
        echo !COM_M!
        rem some data process
    )
    popd
)
endlocal

Read this answer for details about the commands SETLOCAL and ENDLOCAL. The second line is required because of definition of environment variables inside a command block referenced also from within the command block. The disadvantage is that directory and file names containing one or more ! are not correct processed by this batch file because of enabled delayed expansion.

It would be better to use in second line at end DisableDelayedExpansion instead of EnableDelayedExpansion and do not define the environment variables COM_DATA, COM_V and COM_M, but use in code not shown %%J, %%I\com-v.dat and %%I\com-M.dat.

The outer FOR loop searches in current directory for any non-hidden subdirectory and runs on each found subdirectory the commands inside outer command block. The current directory can by any directory. It must not be the directory containing the batch file. Use instead of * the string "%~dp0*" to iterate over non-hidden subdirectories in directory of the batch file independent on what is the current directory on starting the batch file. On using just * the directory name without path is assigned to loop variable I. On using "%~dp0*" the directory name with full path is assigned to loop variable I.

pushd "%%I" makes the current subdirectory the current directory for the command process executing the batch file.

The inner FOR loop searches in the current directory for non-hidden files matching the specified wildcard pattern and assigns to loop variable J the file name without path.

Do not use :: as comment. This is an invalid label. Valid and invalid labels inside a command block results in unexpected behavior on execution of the command block. There is the command REM (remark) to write a comment in a batch file. Please note that a command line with command REM is a command line like every other command line and therefore also processed and executed by cmd.exe as described in detail at How does the Windows Command Interpreter (CMD.EXE) parse scripts?

popd restores initial current directory before processing of batch file continues with outer FOR.

endlocal restores initial environment which means all environment variables defined or modified after setlocal are discarded and initial environment variables list is restored as well as initial current directory on starting the batch file and initial states of command extensions and delayed environment variable expansion.

For completes the same batch file with using command DIR twice to iterate over captured lists of directories and file names making it possible to change the list of *.a*.dat files by code of inner FOR loop and add subdirectories to current or batch file directory by inner or outer FOR loop.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "eol=| delims=" %%I in ('dir * /AD-H /B 2^>nul') do (
    echo Processing directory %%~fI ...
    pushd "%%I"
    for /F "eol=| delims=" %%J in ('dir *.a*.dat /A-D-H /B 2^>nul') do (
        set "COM_DATA=%%J"
        echo !COM_DATA!
        set "COM_V=%%I\com-v.dat"
        echo !COM_V!
        set "COM_M=%%I\com-M.dat"
        echo !COM_M!
        rem some data process
    )
    popd
)
endlocal

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.

  • dir /?
  • echo /?
  • endlocal /?
  • for /?
  • popd /?
  • pushd /?
  • rem /?
  • set /?
  • setlocal /?

Read the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background with %ComSpec% /C.

Mofi
  • 46,139
  • 17
  • 80
  • 143
0

This example does the same as your provided code was intended to do, based upon your provided information:

@Echo Off
Set "COM_DATA=%%B"
Set "COM_V=%%A\com-v.dat"
Set "COM_M=%%A\com-M.dat"
For /D %%A In (*)Do (
    Echo %%A
    For %%B In ("%%A\*.a*.dat")Do (
        Echo %COM_DATA%
        Echo %COM_V%
        Echo %COM_M%
        Rem Some data process
    )
)
Pause

Once you're satisfied with the output from running the code, (before any modification), you can, if you wish, remove all of the Echo and Rem lines. I have not used the PushD and PopD commands, as I saw no reason for their use, given the provided information. I also set the variables outside of the For blocks, because it means they'll only need setting once, not on every iteration, and it removes the need to delay expansion.

You may need to consider changing each instance of %%A to %%~fA if your process code requires full paths.

Compo
  • 36,585
  • 5
  • 27
  • 39