Endlocal & "set var" not working as expected in "for" loop - batch-file

I'm doing a job, copying files from one location to another location using BATCH file. I split my statements into three parts, one program driver, one for generating file list under each sub-directory, and one for checking file name & doing actual copy stuff.
1.PROGRAM DRIVER
IF EXIST TEMP.TXT DEL TEMP.TXT
CD>TEMP.TXT
set /p ROOT=<TEMP.TXT
rem PARA is the date to copy
SET PARA=2013-08-06
ECHO %PARA%
CD %ROOT%\%PARA%
FOR /R %%A IN (.) DO ( ::COPY SUB-LOGIC FILE TO EACH SUB-DIRECTORY
ECHO NOW IN %%A
CD %%A
XCOPY "%ROOT%\WORK.BAT" . /K /Y
XCOPY "%ROOT%\CORE.BAT" . /K /Y
ECHO LOOP OUT.
)
CD %ROOT%\%PARA%
FOR /R %%A IN (.) DO (
ECHO NOW IN %%A
CD %%A
CALL WORK.BAT ::GENERATING FILE LIST
ECHO LOOP OUT.
)
CD %ROOT%\%PARA%
FOR /R %%A IN (.) DO (
ECHO NOW IN %%A
CD %%A
CALL CORE.BAT ::DOING COPY STUFF
ECHO LOOP OUT.
)
PAUSE
2.WORK.BAT
IF EXIST FILE.TXT DEL FILE.TXT
FOR %%B IN (*.wav) DO ECHO %%~nxB>>FILE.TXT
3.COPYING STUFF
FOR %%F IN ("%CD%") DO SET CURDIR=%%~nxF
IF NOT EXIST FILE.TXT GOTO END
SET CCC="FALSE" ::IF NO CCC DECLARED HERE,BELOW FOR LOOP WILL BE SKIPPED
PAUSE
FOR /F %%C IN (FILE.TXT) DO (
SETLOCAL
SET RES="FALSE"
IF "%%C" GEQ "CH201_00000000_000.WAV" SET RES="TRUE"
IF "%%C" LEQ "CH300_FFFFFFFF_FFF.WAV" (
SET RES="TRUE"
) ELSE ( SET RES="FALSE")
ENDLOCAL& SET CCC=%RES% *::VAR CCC NOT UPDATED*
PAUSE
IF %CCC% EQU "TRUE" (
IF NOT EXIST D:\PHILIPS\%PARA%\%PARA%\%CURDIR% MD D:\PHILIPS\%PARA%\%PARA%\%CURDIR%
XCOPY "%ROOT%\%PARA%\%CURDIR%\%%C" D:\PHILIPS\%PARA%\%PARA%\%CURDIR% /K /Y
)
)
:END
ECHO LOOP OUT
My question is, why my "ENDLOCAL & SET" statement not working, i.e., NULL each time, as pictures show. How can I change my statements to make it work as expected?
I changed part 3 to
FOR %%F IN ("%CD%") DO SET CURDIR=%%~nxF
IF NOT EXIST FILE.TXT GOTO END
SET "RES="
PAUSE
FOR /F %%C IN (FILE.TXT) DO (
SET "RES="
IF "%%C" GEQ "CH201_00000000_000.WAV" SET "RES=Y"
IF "%%C" LEQ "CH300_FFFFFFFF_FFF.WAV" (
SET "RES=Y"
) ELSE ( SET "RES=" )
PAUSE
IF DEFINED RES (
IF NOT EXIST D:\PHILIPS\%PARA%\%PARA%\%CURDIR% MD D:\PHILIPS\%PARA%\%PARA%\%CURDIR%
XCOPY "%ROOT%\%PARA%\%CURDIR%\%%C" D:\PHILIPS\%PARA%\%PARA%\%CURDIR% /K /Y
)
)
It seems that RES always defined, even FILENAME is in specified ranges. In this case, it copied wrong files.

in (3)
FOR /F %%C IN (FILE.TXT) DO (
SETLOCAL
SET RES="FALSE"
IF "%%C" GEQ "CH201_00000000_000.WAV" SET RES="TRUE"
IF "%%C" LEQ "CH300_FFFFFFFF_FFF.WAV" (
SET RES="TRUE"
) ELSE ( SET RES="FALSE")
ENDLOCAL& SET CCC=%RES% *::VAR CCC NOT UPDATED*
PAUSE
IF %CCC% EQU "TRUE" (
IF NOT EXIST D:\PHILIPS\%PARA%\%PARA%\%CURDIR% MD D:\PHILIPS\%PARA%\%PARA%\%CURDIR%
XCOPY "%ROOT%\%PARA%\%CURDIR%\%%C" D:\PHILIPS\%PARA%\%PARA%\%CURDIR% /K /Y
)
)
Within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed - the same thing applies to a FOR ... DO (block).
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.
Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the changed value of var or 2) to call a subroutine to perform further processing using the changed values.
Note therefore the use of CALL ECHO %%var%% which displays the changed value of var. CALL ECHO %%errorlevel%% displays, but sadly then RESETS errorlevel.
Where flags are involved, the situation changes again. set "flag=" will ensure a flag is cleared. set "flag=somethingelse" will ensure it is set (the value is not relevant.) Using if defined flag (doiftrue) else (doiffalse) works on the run-time (current) status of flag - not the parse-time value.
Hence, I suggest you change your processing, setting ccc to either nothing with a set "ccc=" statement or something with a set "ccc=y" and you can then test for true/false using if [not] defined ccc
The syntax SET "var=value" (where value may be empty) is used to ensure that any stray trailing spaces are NOT included in the value assigned. set /a can safely be used "quoteless".
(on revised code)
Your tests are incorrect.
res will not be set to Y with value CH145... against CH201...
But it will be set to Y in the LEQ test as CH145... is lestt than or equal to CH300...
You may either cascade the setting:
if "%%C" GEQ "CH201..." IF "%%C" LEQ "CH300..." set "res=Y"
or gate the test
IF "%%C" GEQ "CH201_00000000_000.WAV" SET "RES=Y"
if defined res IF "%%C" GTR "CH300_FFFFFFFF_FFF.WAV" SET "RES="

Related

Pass Named Parameters to Batch Script with Special Characters

I found and modified a code snippet to allow passing unlimited named parameters to a batch script.
Accessing unknown number of commands (parameters) in batch file
Everything was working great, but now I'm building in Wildcard checking into the script and I found if I pass a value like this "FILEPATH=C:\tmp\test *.txt" that FILEPATH doesn't get defined by my code snippet. As I didn't truly create it I am partly unaware of how it works and could be modified to allow special characters.
Here is the code snippet to allow named params that I'd like guidance on modifiying:
::Set Named Arguments
set argCount=0
for %%x in (%*) do (
set /A argCount+=1
set "argVec[!argCount!]=%%~x"
set %%x
)
Update:
I changed the for loop to for /F delims^=^"^ tokens^=* %%x in (%*) do ( and it will now define the FILEPATH with a WILDCARD, but it strips the first " and then makes all the arguments into one line and also strips the final ". Perhaps I need a way to use the argcount to correlate the alphanumeric position of the set %%x line?
Another thought, since the above change to the for loop does accept the wildcard, but creates a single long variable containing all params passed to script.cmd, perhaps I can loop over it (the long variable) again and split up the named arguments.
Update:
Example usage:
script.cmd:
#ECHO OFF
CLS
::Set Named Arguments
set argCount=0
for %%x in (%*) do (
set /A argCount+=1
set "argVec[!argCount!]=%%~x"
set %%x
)
ECHO %FILEPATH%
ECHO %VAR%
EXIT /B
test.cmd:
#ECHO OFF
CLS
::Doesn't Work
CALL "C:\tmp\script.cmd" "FILEPATH=C:\tmp\tes*.txt" "VAR=2"
PAUSE
::Works Fine
CALL "C:\tmp\script.cmd" "FILEPATH=C:\tmp\test.txt"
PAUSE
Using your current method by defining FILEPATH= as a parameter.
Note:
I need to express that this is trending a little on the dangerous side. Reason being, if any of the input variables contains something like PATH=Somepath it will break the immediate environment while the script is running. So ensure you check the input types that will be passed.
#echo off & setlocal enabledelayedexpansion
(set "%~1" & set "%~2" & set "%~3" & set "%~4")>nul
set argCount=0
if defined FILEPATH (
for %%x in ("%FILEPATH%") do (
set /A argCount+=1
set "argVec[!argCount!]=%%~x"
echo argVec[!argCount!]
)
echo %FILEPATH%
) else (
echo FILEPATH not defined
)
My full solution based on #Gerhard's awesome answer. This still allows me to take an unlimited amount of variables input in unknown order in "VALUE=KEY" format, and not know the FILEPATH positional argument, but as batch has limitations on using only %1-->%9 I felt it easiest/best to handle/allow that FILEPATH be any of the first 9 PARAMS. This really taught me about the things you take for granted in shells like BASH and also, what BASH is doing "behind the scenes". The idea was to build in wildcard searching as my script.cmd will always be called by a "parent script" w/ params and I want it to be similar to BASH (allow end users to use wildcards).
script.cmd:
#ECHO OFF
CLS
::SET Named Arguments
SET argCount=0
for %%x in (%*) do (
SET /A argCount+=1
SET "argVec[!argCount!]=%%~x"
SET %%x
)
::Wildcards in FilePath?
(SET "%~1" & SET "%~2" & SET "%~3" & SET "%~4" & SET "%~5" & SET "%~6" & SET "%~7" & SET "%~8" & SET "%~9")>nul
SET argCount=0
IF DEFINED FILEPATH (
FOR %%x IN ("%FILEPATH%") DO (
SET /A argCount+=1
SET "argVec[!argCount!]=%%~x"
)
CALL :FindFileWildCard "%FILEPATH%" FILEPATH
) ELSE (
ECHO No "FILEPATH=C:\path\print.doc" Defined!
PAUSE
GOTO:EOF
)
ECHO %FILEPATH%
ECHO %VAR%
ECHO %VAR2%
ECHO %VAR3%
ECHO %VAR4%
ECHO %VAR5%
ECHO %VAR6%
ECHO %VAR7%
ECHO %VAR8%
ECHO %VAR9%
ECHO %VAR10%
GOTO :EOF
::Functions
:FindFileWildCard
::Does Path contain WildCards?
ECHO "%~1" | FIND /i "*" >nul
IF %ERRORLEVEL% EQU 0 (
FOR /F "Tokens=*" %%F IN ('DIR /B /S "%~1"') DO (
SET %2=%%F
EXIT /B
)
)
ECHO "%~1" | FIND /i "?" >nul
IF %ERRORLEVEL% EQU 0 (
FOR /F "Tokens=*" %%F IN ('DIR /B /S "%~1"') DO (
SET %2=%%F
EXIT /B
)
)
EXIT /B
:EOF
test.cmd:
#ECHO OFF
CLS
CALL "C:\tmp\script.cmd" "VAR=VAR" "VAR2=VAR2" "VAR3=VAR3" "FILEPATH=C:\tmp\tmp space\te*.txt" "VAR4=VAR4" "VAR5=VAR5" "VAR6=VAR6" "VAR7=VAR7" "VAR8=VAR8" "VAR9=VAR9" "VAR10=VAR10"
PAUSE
CALL "C:\tmp\script.cmd" "VAR=VAR" "VAR2=VAR2" "VAR3=VAR3" "FILEPATH=C:\tmp\tmp space\test with spa?*.txt" "VAR4=VAR4" "VAR5=VAR5" "VAR6=VAR6" "VAR7=VAR7" "VAR8=VAR8" "VAR9=VAR9" "VAR10=VAR10"
PAUSE
CALL "C:\tmp\script.cmd" "VAR=VAR" "VAR2=VAR2" "VAR3=VAR3" "FILEPATH=C:\tmp\test.txt" "VAR4=VAR4" "VAR5=VAR5" "VAR6=VAR6" "VAR7=VAR7" "VAR8=VAR8" "VAR9=VAR9" "VAR10=VAR10"
PAUSE
Result:
C:\tmp\tmp space\test with space.txt
VAR
VAR2
VAR3
VAR4
VAR5
VAR6
VAR7
VAR8
VAR9
VAR10
Press any key to continue . . .

sorter using scored keywords is acting up, and cannot echo without failing

this script sorts files into known subdirectories fast, by using database files filled with scored keywords. it works for the most part but sometimes it gives me errors that I can't figure out because it acts differently when the echo is turned on, and fails. this code is very important to me so this is a huge problem for me. the echo issue has to be fixed or it's unmanageable, no other possible problems need be addressed in this question! please help, it's largely beyond my understanding.
:: sorts files from %cd% into known subdirs according to database of scored keywords. minimum score is 2.0
rem todo if echo is on it fails with certain keywords like a simple *1x0* which is super weird
rem sometimes outputs unlocated error missing operator while still doing its job correctly
rem sometimes outputs unlocated error the system cannot fing the path specified
rem keywords or subdir names cannot contain spaces
rem fails with filenames with irregular dash characters
rem Adds * to start and end of keyword. start/end wildcards should be used surgically in the keywords file instead
dir *.* /a-d >nul 2>nul || exit /b
set "tempfile=%temp%\sortables"
set "sourcedir=%~1"
setlocal enabledelayedexpansion
rem set datafile, categories according to current location
set "categories="
if /i "%cd%"=="d:\videos" (
set "datafile=videos"
set "categories=series porno"
)
if /i "%cd%"=="d:\videos\movies" (
set "datafile=movies"
set "categories=features psychedelic pornography concerts standup featurettes documentaries"
)
if /i "%cd%"=="d:\videos\movies\documentaries" (
set "datafile=docu"
set "categories=1-scarcity 2-globalists 3-disinformation 4-agendas 5-abundance"
)
if /i "%cd%"=="d:\videos\movies\features" (
set "datafile=films"
set "categories=comedy drama action thriller venture crime horror mystery fantasy science western warfare"
)
if /i "%cd%"=="d:\videos\series" (
set "datafile=series"
set "categories=comedy stories reality trippy"
)
if /i "%cd%"=="d:\videos\series\comedy" (
set "datafile=comedy"
set "categories=cartoon classic modern reality sketch standup"
)
if /i "%cd%"=="d:\videos\series\pilots" (
set "datafile=pilots"
set "categories=reality drama comedy scifi fantasy crime mystery action thriller"
)
if /i "%cd%"=="d:\videos\shorts" (
set "datafile=shorts"
set "categories=psychedelic entertaining music media useful conspiracies"
)
if /i "%cd%"=="d:\videos\shorts\media" (
set "datafile=media"
set "categories=trailers games fandom extras facts analysis features"
)
if /i "%cd%"=="d:\videos\shorts\music" (
set "datafile=music"
set "categories=bigbeat classical clubbing country electro swing reggae dub experimental geeky metal rap rock synthwave triphop xxx"
)
if not defined categories exit /b
set database=d:\system\scripts\%datafile%.txt
if not exist "%database%" echo critical error: database %datafile%.txt doesn't exist && exit /b
if defined verbal echo sorting "%cd%"
rem =============================================================================================================================
rem setup sorting categories (do not change anything lightly or without backup after this point)
rem =============================================================================================================================
set "sortingcategories="
for %%a in (%categories%) do set "sortingcategories=!sortingcategories!,%%~a"
set "sortingcategories=%sortingcategories: =_%"
rem =============================================================================================================================
rem create tempfile containing lines of: name|sortingcategory|weight
rem =============================================================================================================================
(
for /f "tokens=1,2,*delims=," %%s in (%database%) do (
set "sortingcategory=%%s"
set "sortingcategory=!sortingcategory: =_!"
for /f "delims=" %%a in (
'dir /b /a-d "%sourcedir%\*%%u*" 2^>nul'
) do (
echo %%a^|!sortingcategory!^|%%t^|%%s^|%%u
)
)
)>"%tempfile%"
type "%tempfile%" >>d:\system\scripts\sorter.log
rem =============================================================================================================================
rem reset and call processing for each file in tempfile + dummy (helps counting the last score?)
rem =============================================================================================================================
set "lastname="
echo off
for /f "tokens=1,2,3,*delims=|" %%a in ('sort "%tempfile%"') do call :resolve %%b %%c "%%a"
call :resolve dummy 0
rem declare failures
if defined verbal if not "%datafile%"=="videos" if not "%datafile%"=="music" if not "%datafile%"=="media" (
dir "%~1\*" /a-d >nul 2>nul && for /f "delims=" %%q in ('dir %1 /b /a-d') do echo unsortable in %datafile% "%%q"
)
exit /b
:resolve
IF "%~3" equ "%lastname%" GOTO accum
rem report and reset accumulators
IF NOT DEFINED lastname GOTO RESET
SET "winner=none"
SET /a maxfound=1
FOR %%v IN (%sortingcategories%) DO (
FOR /f "tokens=1,2delims=$=" %%w IN ('set $%%v') DO IF %%x gtr !maxfound! (SET "winner=%%v"&SET /a maxfound=%%x)
)
if "%winner%"=="none" goto reset
SET "winner=%winner:_= %"
SET "lastname=%lastname:&=and%"
rem this has a problem with different type of dash -
rem this once overwrote a same-name, much smaller file, wtf?
if "%winner%"=="porno" move "%sourcedir%\%lastname%" "d:\nvidia\" >nul && echo "d:\nvidia\%lastname%"
if not "%winner%"=="porno" move "%sourcedir%\%lastname%" "%sourcedir%\%winner%\" >nul && echo "%sourcedir%\%winner%\%lastname%"
if "%winner%"=="features" if exist "%sourcedir%\%lastname%" move "%sourcedir%\%lastname%" "%sourcedir%\%winner%\" >nul && echo "%sourcedir%\%winner%\%lastname%"
rem before or after successful filing we could do a surgical dupe check for only that file, rendering the old style obsolete
:RESET
FOR %%v IN (%sortingcategories%) DO SET /a $%%v=0
SET "lastname=%~3"
:accum
SET /a $%1+=%2
with echo turned on the error looks like this (note that this works fine when echo is off)
d:\VIDEOS>for /F "tokens=1,2,3,*delims=|" %a in ('sort "E:\TEMP\sortables"') do call :resolve %b %c "%a"
d:\VIDEOS>call :resolve !sortingcategory! 2 " for /F "delims=" %a in ('dir /b /a-d "\*1x0*" 2>nul') do (echo %a"
The syntax of the command is incorrect.
d:\VIDEOS>IF " for /F "delims" equ "" GOTO accum
d:\VIDEOS>
and this is the database file used (sorry for the lingo)
series,2,1x0
series,2,1x1
series,2,2x0
series,1,s0
series,1,s1
series,1,s2
series,1,s3
series,1,s4
series,1,s5
series,1,s6
series,1,s7
series,1,s8
series,1,s9
series,-1,s00
series,-1,e00
series,1,e0
series,1,e1
series,1,e2
series,1,e3
series,1,e4
series,1,e5
series,1,e6
series,1,e7
series,1,e8
series,1,e9
series,-1,extras
series,1,judge?judy?s
series,1,pilot
porno,1,amateur
porno,1,wet
porno,1,wmv
porno,1,xxx
missing,0,not appearing in this directory
it takes files from d:\videos and sorts them into d:\videos\series or d:\nvidia (hidden alternative to the other subdir d:\videos\porno)
rem =============================================================================================================================
rem create tempfile containing lines of: name|sortingcategory|weight
rem =============================================================================================================================
(
for /f "tokens=1,2,*delims=," %%s in (%database%) do (
set "sortingcategory=%%s"
set "sortingcategory=!sortingcategory: =_!"
for /f "delims=" %%a in (
'dir /b /a-d "%sourcedir%\*%%u*" 2^>nul'
) do (
echo %%a^|!sortingcategory!^|%%t^|%%s^|%%u
)
)
)>"%tempfile%"
change to
rem =============================================================================================================================
rem create tempfile containing lines of: name|sortingcategory|weight
rem =============================================================================================================================
(
for /f "usebackq tokens=1,2,* delims=," %%s in ("%database%") do (
set "sortingcategory=%%s"
set "sortingcategory=!sortingcategory: =_!"
for /f "delims=" %%a in (
'dir /b /a-d "%sourcedir%\*%%u*" 2^>nul'
) do (
>&3 echo %%a^|!sortingcategory!^|%%t^|%%s^|%%u
)
)
) 3>"%tempfile%"
Prior, echo off setting allows the echoed text
to be redirected to file from stream 1.
When you set echo on, stream 1 includes the commands
being echoed as well as the echoed text.
To avoid this merged output of commands and text,
use an auxiliary stream. CMD supports auxiliary
streams 3 through to 9.
The changed code sets the echoed text to redirect
to the handle of stream 3 (>&3).
The redirection to the file uses stream 3 (3>).
The errors posted is a delayed effect caused by
echoed commands and text written to %tempfile%
when using echo on with your posted code.
Added for loop option usebackq so the %database%
path can be double quoted.

check for spaces in file name inside of for loop in batch file

I have a batch script that is calling a VBscript file. It reiterates through all files in a watched folder.
It needs to verify if the file name has spaces in it and if so reject the file and not process it with the VBS.
I must have an error on the code as I get the error message:
ELSE was not expected at this time.
I have looked at the documentation and searched for the answer for quite some time, including this question: check "IF" condition inside FOR loop (batch/cmd)
But still, I can't see what is wrong in my syntax:
#ECHO OFF
setlocal ENABLEDELAYEDEXPANSION
call :ReadIni Infolder inFolder
call :ReadIni Outfolder outFolder
echo %inFolder%
echo %outFolder%
pause
:StartLoop
FOR %%I in (%inFolder%\*.srt) DO (
ECHO %%I
ECHO %%~nxI
SET TESTNAME=%%~nxI
ECHO !TESTNAME!
ECHO !TESTNAME: =_!
PAUSE
IF NOT !TESTNAME!==!TESTNAME: =_! (
move "%~sdp0%%~nxI" "%outFolder%\ERROR_IN_FILE_NAME_%%~nxI"
) ELSE (
copy /y "%%I" "%~sdp0%%~nxI"
%~sdp0SRToffset.vbs "%~sdp0%%~nxI" "%~sdp0%%~nxI"
IF %ERRORLEVEL%==1 (
Goto StartLoop
) else (
move "%~sdp0%%~nxI" "%outFolder%\"
move "%~sdp0QC_%%~nxI" "%outFolder%\"
del "%%I"
)
)
)
timeout /t 1
goto StartLoop
:ReadIni
FOR /F "tokens=2 delims==" %%a in ('find "%~1=" config.ini') do set %~2=%%a
exit /b
Any help would be appreciated.
IF NOT "!TESTNAME!"=="!TESTNAME: =_!" (
...
IF %ERRORLEVEL%==1 (
Quoting the strings causes cmd to regard the string as a single entity.
Note that the following if %errorlevel% will be executed using the value of errorlevel at :startloop. (See delayed expansion for reasoning.)
Cure by using if !errorlevel!==1 (. (Using the runtime value of errorlevel as established by the vbs routine.)

Delayed expansion and exclamation marks in strings

Ok, so I'm still pretty new to batch scripting and I have this problem with my code that I'm using setlocal enabledelayedexpansion in my code for the for loop, the For loop goes through folder names in a specific directory, but the problem is that some of the names may include "!"(exclamation marks) and if that is the case they are not counted for in the "!filename!" and when the code creates a new directory it does not include the "!". Also when the xcopy tries to copy the files from the original folder, the folder is not found, because the variable "!filename!" is not the same as the original(does not have the exclamation point).
So I found that for this I need to only add "setlocal enable delayed expansion" to some parts of the code and turn it off at other, but I cant seem to find the right places.
The code:
#ECHO OFF
setlocal enabledelayedexpansion
SET Location_Folder=V:
SET Destination_folder=V:\Nonimportable
SET Check_file_validation=V:\Nonimportable\result.txt
SET Excluded_folder=Nonimportable
set "lineNr=12"
For /f "tokens=*" %%O in ('dir /b /a:d "%Location_Folder%"') do (
set filename=%%O
call D:\somefolder\otherfolder\batscriptname.bat !filename!
set Validation=
echo !filename!| FINDSTR /i /c:"%Excluded_folder%" >NUL
IF ERRORLEVEL 1 (
for /F "skip=12 delims=" %%a in (%Check_file_validation%) do if not defined Validation (
set Validation=%%a
call :valid
)
) else (
echo This folder name is excluded: !filename!
)
)
goto Finish
:valid
echo !Validation!| FINDSTR /c:"1" >NUL
if ERRORLEVEL 1 (
set Folder_path=%Location_Folder%\!filename!
set New_Folder_path=%Destination_folder%\!filename!
mkdir "!New_Folder_path!"
echo D | xcopy /o /y /q /s /v "!Folder_path!" "!New_Folder_path!"
rmdir /s /q "!Folder_path!"
) else (
echo Folder is valid !filename!
goto Finish
)
:Finish
exit /b
The Call part calls another small (~5lines) batch file that checks the sqlplus server if the "!filename!" is valid
EDIT: The whole code works fine and does what it should, unless there is a "!" in the name of some folder.
The problem is the parameter expansion in set filename=%%O.
In %%O is still the exclamation mark, but when delayed expansion is enabled, the bangs are dropped.
The conclusion is simple, delayed expansion have to be disabled when you expand a FOR parameter.
But when you also need delayed expansion?
You simply toggle the mode.
setlocal DisableDelayedExpansion
For /f "tokens=*" %%O in ('dir /b /a:d "%Location_Folder%"') do (
set "filename=%%O" -- Here the DelayedExpansion have to be disabled
setlocal EnableDelayedExpansion
call D:\somefolder\otherfolder\batscriptname.bat filename
set "Validation="
...
endlocal
)
See also my modification of the CALL myBat.bat filename instead of CALL myBat.bat !filename!.
You shouldn't use content with CALL, better use a variable by reference and in your function take the content by
set "_filename=!%1!"
It's because CALL itself has some nasty behaviour with spaces, carets, etc
If you use a variable within a code block (parenthesised series of commands) then %var% will yield the value of the variable when the block is originally encountered (ie parse-time value) and !var! the value of the variable as it changes during the block (ie "run-time" value).
If you call a procedure - internal or external, then the values of the variables that the procedure sees are the run-time values from the parent. If these values are changed within the called procedure then the same rules apply, and the changed values are returned to the parent procedure.
However if you invoke setlocal then any value-variation made is reverted to its original value if you execute an endlocal instruction or reach end-of-file within the context of the setlocal.
OK - so that's how delayedexpansion works.
In your case, there is no need for delayedexpansion at all. In the loop in the mainline (%%O) you can use %%O in place of !filename!. In the :valid procedure, you can move the two set commands outside of the code block and then there's no need at all to use !vars! since no access is required to variables whose values change within blocks.
#ECHO OFF
setlocal
SET Location_Folder=V:
SET Destination_folder=V:\Nonimportable
SET Check_file_validation=V:\Nonimportable\result.txt
SET Excluded_folder=Nonimportable
set "lineNr=12"
For /f "tokens=*" %%O in ('dir /b /a:d "%Location_Folder%"') do (
set filename=%%O
call D:\somefolder\otherfolder\batscriptname.bat %%O
set Validation=
echo %%O| FINDSTR /i /c:"%Excluded_folder%" >NUL
IF ERRORLEVEL 1 (
for /F "skip=12 delims=" %%a in (%Check_file_validation%) do if not defined Validation (
set Validation=%%a
call :valid
)
) else (
echo This folder name is excluded: %%O
)
)
goto Finish
:valid
set Folder_path=%Location_Folder%\%filename%
set New_Folder_path=%Destination_folder%\%filename%
echo %Validation%| FINDSTR /c:"1" >NUL
if ERRORLEVEL 1 (
mkdir "%New_Folder_path%"
echo D | xcopy /o /y /q /s /v "%Folder_path%" "%New_Folder_path%"
rmdir /s /q "%Folder_path%"
) else (
echo Folder is valid %filename%
rem redundant instruction : goto Finish
)
:Finish
exit /b

Batch-file for-loop and use of delims

I have created a batch file in a windows server to parse the name of the files stored in a folder.
The name of the file contains a set of parameters splitted by the hyphen, e.g.
ACC-INV-APR-2015
I need to check the syntax correctness of the first two parameters (department and document type) e.g. I would avoid that the hyphen is inserted more than a time in the file name.
On the basis of the check, the files with wrong syntax will be moved to a folder.
We have to consider that, apart the first two parameters that are mandatory, the other ones could be skipped and therefore the file name could have some repetitive hypens after the first two parameters, e.g.
FIN-DOC-APR-2015--MFH-P01
We would avoid to have some file name like: FIN--DOC-APR-2015-MFH-P01
I have created the following batch file but I don't know how to skip the filename with wrong syntax....
Thank you.
setlocal EnableDelayedExpansion
set source=\\fileserver\share$\archive
set dest_ok=\\fileserver\share$\fileok
set dest_not=\\fileserver\share$\error
FOR /R %source% %%f in (*.*) do call :Proc1 "%%f"
goto End
:Proc1
Set filename=%1%
For %%A in (%filename%) do (
Set Folder="%%~dpA"
Set Name=%%~nxA
)
for /f "tokens=1,2 delims=- " %%a in ("%Name%") do call :Proc2 %%a %%b
goto :eof
:Proc2
set department=%1
set typedoc=%2
FINDSTR /x "%department%" c:\0_scripts\arch\departments.txt
if %errorlevel%==0 FINDSTR /x "%typedoc%" c:\0_scripts\arch\typedocs.txt
if %errorlevel%==0 move /Y %filename% %dest_ok%
if %errorlevel%==1 move /Y %filename% %dest_not%
goto :eof
:End
Sounds like a job for regular expressions. The Windows utility findstr will let you match based on a regular expression. It exits status 0 if found, non-zero otherwise. This lends itself to conditional execution. In a cmd console, enter findstr /? for details on supported regexp syntax.
It'll also speed things up to cache the contents of departments.txt and typedocs.txt into variables, rather than open, read, close, repeat for each file checked.
So, with that in mind, here's how I'd do it:
#echo off
setlocal
set "source=\\fileserver\share$\archive"
set "dest_ok=\\fileserver\share$\fileok"
set "dest_not=\\fileserver\share$\error"
set "departments.txt=c:\0_scripts\arch\departments.txt"
set "typedocs.txt=c:\0_scripts\arch\typedocs.txt"
setlocal enabledelayedexpansion
for /f "usebackq delims=" %%I in ("%departments.txt%") do set "dept=%%~I;!dept!"
for /f "usebackq delims=" %%I in ("%typedocs.txt%") do set "type=%%~I;!type!"
endlocal & set "dept=%dept%" & set "type=%type%"
for /r "%source%" %%I in (*) do (
rem // Does filename match /^[a-z]+-[a-z]+/i ?
echo %%~nxI | findstr /i "^[a-z][a-z]*-[a-z][a-z]*" >NUL && (
rem // Yep. Check whether department and doc type is in allowed list.
for /f "tokens=1-2 delims=- " %%a in ("%%~nxI") do (
// if %dept% doesn't equal itself with %%~a removed, and so on...
setlocal enabledelayedexpansion
if not "%dept%"=="!dept:%%~a=!" if not "%type%"=="!type:%%~b=!" (
// All checks passed. Moved to OK folder.
move /y "%%~fI" "%dest_ok%"
)
endlocal
)
)
// If the file hasn't been moved by now, it must've failed a test.
if exist "%%~fI" move /y "%%~fI" "%dest_not%"
)
C:\0_scripts\arch>(
echo MFH3-FHW-20150529-F001MD14895-20301231-V01-OP20-TRIFLEX-CP1_H--.pdf | findstr /i "^[a-z][a-z]*-[a-z][a-z]*" 1>N
UL && (for /F "tokens=1-2 delims=- " %a in ("MFH3-FHW-20150529-F001MD14895-20301231-V01-OP20-TRIFLEX-CP1_H--.pdf") do (
setlocal enabledelayedexpansion
if not "TEF6;TEF10;QMM8;QMM73;QMM72;QMM71;QMM7;QMM6;QMM13;QMM1;QMM;MFP2;MFP1;MFH3;MFH2;MFH1;MFH ;MFG3;MFG22;MFG21;MFG2;
MFG11;MFG1;MFG;MFB;HSE;COS;" == "!dept:%~a=!" if not "WPL;WP;WBP;WB;WAL;WAG;WA;VTL;VTK;VDP;VBT;VBL;VB;VAW;VAP;VA;UVA;UMV
;TSS;TRN;TKU;TDC;SYM;SWD;SWC;SW;SVS;SVA;SV;STR;STL;STF;STB;SPC;SBT;SAM;RTZ;RTP;RPL;RP;RNO;RHW;RAW;QMP;QMA;QM;QBG;QB;QAM;
PZB;PUM;PRV;PRS;PRJ;PRA;PQP;PPM;PPK;PP;PNR;PLB;PH;PFH;PDV;PDR;PDC;PDB;PAP;PAL;PAG;OPS;OPL;OEE;NOR;NKA;MUB;MSZ;MON;MOD;MB
B;MNT;LZT;LZS;LZN;LPV;LPN;LPL;LPC;LPA;LHT;LDP;LBA;KSB;KPV;KPA;KOE;KOB;KBU;KBL;KB;IAM;HZG;HZ;HSE;HRB;HFG;HF;HE;HAZ;GMD;GE
Z;GBB;FVT;FRM;FPL;FPK;FPI;FPA;FP;FMP;FME;FMD;FMA;FLP;FLB;FIM;FHW;FGY;FGV;FGS;FGP;FGL;FGK;FGE;FGD;FGB;FGA;FDA;FA;EZZ;EWZ;
EWS;EVT;EV;ETZ;ETL;ESZ;EPB;EP;ECM;DVL;ECR;DV;DRX;DRW;DRV;DRQ;DRK;DRF;DMD;DIF;DLP;DER;DDI;DBL;DB;DAT;D01;CPC;CIP;CHL;CE;C
AP;BVT;BVS;BVB;BV;BUG;BSV;BST;BSS;BS;BPZ;BLD;BDL;BBL;BBD;BB;BAL;BAD;ANH;AGZ;AFK;AEN;AED;AAW;AA;" == "!type:%~b=!" (
move /y "\\server1\digit$\deposito\MFH3\MFH3-FHW-20150529-F001MD14895-20301231-V01-OP20-TRIFLEX-CP1_H--.pdf" "\\server1\digit$\errori"
pause
)
endlocal
) )
if exist "\\server1\digit$\deposito\MFH3\MFH3-FHW-20150529-F001MD14895-20301231-V01-OP20-TRIFLEX-CP1_H--.pdf" move
/y "\\server1\digit$\deposito\MFH3\MFH3-FHW-20150529-F001MD14895-20301231-V01-OP20-TRIFLEX-CP1_H--.pdf" "\\server11\digit$\ok"
pause
)
1 file(s) moved.
Press any key to continue . . .
Blockquote
I have changed the script and came back to your original version .
This is the output of the batch file when a file correct is processed:
if exist "\server1\digit$\deposito\MFH3\MFH3--FHW-20150512-F01MD14861-20301231-V02-OP20-TRIFLEX-CP1H--.pdf" move
/y "\server1\digit$\deposito\MFH3\MFH3--FHW-20150512-F01MD14861-20301231-V02-OP20-TRIFLEX-CP1H--.pdf" "\server1\
digit$\errori"
pause
)
1 file(s) moved.
Press any key to continue . . .
C:\0_scripts\arch>(
echo MFH3-AFK-20150511-F01MD12340-20301231-V07-OP20-TRIFLEX-CP1_H--.pdf | findstr /i "^[a-z][a-z]-[a-z][a-z]" 1>NU
L && (for /F "tokens=1-2 delims=- " %a in ("MFH3-AFK-20150511-F01MD12340-20301231-V07-OP20-TRIFLEX-CP1_H--.pdf") do (
setlocal enabledelayedexpansion
if not "TEF6;TEF10;QMM8;QMM73;QMM72;QMM71;QMM7;QMM6;QMM13;QMM1;QMM;MFP2;MFP1;MFH3;MFH2;MFH1;MFH ;MFG3;MFG22;MFG21;MFG2;
MFG11;MFG1;MFG;MFB;HSE;COS;" == "!dept:%~a=!" if not "WPL;WP;WBP;WB;WAL;WAG;WA;VTL;VTK;VDP;VBT;VBL;VB;VAW;VAP;VA;UVA;UMV
;TSS;TRN;TKU;TDC;SYM;SWD;SWC;SW;SVS;SVA;SV;STR;STL;STF;STB;SPC;SBT;SAM;RTZ;RTP;RPL;RP;RNO;RHW;RAW;QMP;QMA;QM;QBG;QB;QAM;
PZB;PUM;PRV;PRS;PRJ;PRA;PQP;PPM;PPK;PP;PNR;PLB;PH;PFH;PDV;PDR;PDC;PDB;PAP;PAL;PAG;OPS;OPL;OEE;NOR;NKA;MUB;MSZ;MON;MOD;MB
B;MNT;LZT;LZS;LZN;LPV;LPN;LPL;LPC;LPA;LHT;LDP;LBA;KSB;KPV;KPA;KOE;KOB;KBU;KBL;KB;IAM;HZG;HZ;HSE;HRB;HFG;HF;HE;HAZ;GMD;GE
Z;GBB;FVT;FRM;FPL;FPK;FPI;FPA;FP;FMP;FME;FMD;FMA;FLP;FLB;FIM;FHW;FGY;FGV;FGS;FGP;FGL;FGK;FGE;FGD;FGB;FGA;FDA;FA;EZZ;EWZ;
EWS;EVT;EV;ETZ;ETL;ESZ;EPB;EP;ECM;DVL;ECR;DV;DRX;DRW;DRV;DRQ;DRK;DRF;DMD;DIF;DLP;DER;DDI;DBL;DB;DAT;D01;CPC;CIP;CHL;CE;C
AP;BVT;BVS;BVB;BV;BUG;BSV;BST;BSS;BS;BPZ;BLD;BDL;BBL;BBD;BB;BAL;BAD;ANH;AGZ;AFK;AEN;AED;AAW;AA;" == "!type:%~b=!" (
move /y "\server1\digit$\deposito\MFH3\MFH3-AFK-20150511-F01MD12340-20301231-V07-OP20-TRIFLEX-CP1_H--.pdf" "\bars
rv11\digit$\ok"
pause
)
endlocal
) )
if exist "\server1\digit$\deposito\MFH3\MFH3-AFK-20150511-F01MD12340-20301231-V07-OP20-TRIFLEX-CP1_H--.pdf" move
/y "\server1\digit$\deposito\MFH3\MFH3-AFK-20150511-F01MD12340-20301231-V07-OP20-TRIFLEX-CP1_H--.pdf" "\server1\
digit$\errori"
pause
)
1 file(s) moved.
Press any key to continue . . .

Resources