8

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.

Elviox Rance
  • 81
  • 1
  • 4

2 Answers2

6

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

jeb
  • 78,592
  • 17
  • 171
  • 225
2

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 
Magoo
  • 77,302
  • 8
  • 62
  • 84
  • Correct me if I'm wrong, but you are just telling me how the delayed expansion works. But the problem for me is that I can't use variables that contain "!" while I'm using the delayed expansion, because it counts the "!" int the variable as the commands(Or I don't know how to call them), but I don't know how to "fix" my code that the delayed expansion thing would not count the "!" in the variables as "it's" command, but just as a character – Elviox Rance Mar 10 '17 at 11:31