问题
I have folders like E:\Backups\code\Hazard\test1 ... testn
And inside these test folders something like E:\Backups\code\Hazard\test1\it0 ... itn
The root folder is E:\Backups\code from where the code runs.
The below code runs on each subfolders and copies summary.yml from it0 folder to latest it(n) folder.
Why the code runs just for test1 folder and then hangs?
setlocal ENABLEDELAYEDEXPANSION
set root=%cd%
for /D %%X in (%root%\*) do (
echo %%X
cd %%X
for /D /r %%b in (*) do (
cd %%b
echo %%b
for /f "tokens=1,2,*" %%a in ('robocopy . . file.txt /l /nocopy /is /s /nc /ns /ts /ndl /njh /njs ^| sort /r') do set "lastFolder=%%~dpc" & goto :done
:done
echo Last folder : %lastFolder%
for /d %%j in (*) do (
if /i "%%~nj"=="it0" COPY %%j\summary.yml %lastFolder%
)
cd ..
)
)
回答1:
There are two main problems in the code:
- If
gotois used inside aforloop, the loop is cancelled - If you set a variable inside a block of code (code inside parenthesis), to retrieve the value of the variable inside the same block of code you need delayed expansion, enabling it with
setlocal enabledelayedexpansionand changing the syntax used to retrieve the value in the variable from%var%into!var!.
But
- the
gotocan be removed as indicated in the previous answer, - the delayed expansion is not needed. Instead of storing the value from the
forreplaceable parameter inside a variable, just use the replaceable parameter
Not tested, but more or less
@echo off
setlocal enableextensions disabledelayedexpansion
rem E:\Backups\ code \ Hazard \ test1 \ it0 ... itn
rem ^root ^ %%X ^ %%Y ^ %%~dpc
for /D %%X in ("*") do for /D %%Y in ("%%~fX\*") do for /f "tokens=1,2,*" %%a in ('
robocopy "%%~fY." "%%~fY." file.txt /l /nocopy /is /s /nc /ns /ts /ndl /njh /njs
^| sort /r 2^>nul
^| cmd /q /v /c "(set /p .=&echo(!.!)"
') do copy "%%~fY\it0\summary.yml" "%%~dpc."
Being E:\Backups\code the current active directory:
%%Xwill enumerate the folders underE:\Backups\code(Hazard)%%Ywill enumerate the folders underE:\Backups\code\Hazard(testn)%%aexecutes arobocopycommand to locate the folder containing the latestfile.txtfilesort /rsorts the list of files in descending order so the latest file is the first in the listcmdretrieves and outputs only the first line- With all the information available in the several
forreplaceable parameters, execute the indicatedcopycommand.
回答2:
I'm not sure about what the line with robocopy should do. It looks like this command is for getting name of last subdirectory in current directory.
Perhaps this code works better. But I could not test it.
setlocal EnableDelayedExpansion
set "root=%cd%"
for /D %%X in ("%root%\*") do (
echo %%X
cd "%%~X"
for /D /r %%b in (*) do (
cd "%%~b"
echo %%b
call :GetLastFolder
echo Last folder : !lastFolder!
for /d %%j in (*) do (
if /i "%%~nj"=="it0" copy "%%j\summary.yml" "!lastFolder!"
)
cd ..
)
)
goto :EOF
:GetLastFolder
for /f "tokens=1,2,*" %%a in ('robocopy . . file.txt /l /nocopy /is /s /nc /ns /ts /ndl /njh /njs ^| sort /r') do set "lastFolder=%%~dpc" & goto :EOF
goto :EOF
It is at least necessary to reference environment variable lastFolder with exclamation marks instead of percent signs to really use delayed expansion as needed here.
goto :EOF exits the subroutine resulting in continuing on line below call :GetLastFolder.
There is one more goto :EOF or alternatively exit /B after main code necessary to avoid that the code of the subroutine is executed once more after most outer for loop finished. This goto :EOF results in exiting the processing of this batch file.
For understanding the used commands and how they work, open a command prompt window, execute there at least the following commands, and read entirely all help pages displayed for each command very carefully.
call /?for /?goto /?set /?
来源:https://stackoverflow.com/questions/33354048/why-the-loop-is-not-running-as-expected