Mrk
Hi
My first post here.
The code below is a piece of my backup script which, in this case, drives me up the wall:
Code: Select all
setlocal enabledelayedexpansion
[...]
:some_subroutine
md %1\new_dir
for /f "tokens=*" %%i in ('dir "%1" /b') do (
if "%%~ni" neq "new_dir" move "%1\%%i" "%1\new_dir"
)
goto :eof
The problem is that some of the filenames contain exclamation mark which is simply suppressed when processed in my loop and the routine fails to move these files.
I cannot escape exclamation using "^!" in filenames as the list of the files to be processed is unknown prior to this routine.
Anyone? Any help will be appreciated...
----------------------------
#2 05 May 2010 03:54
RG
Mrk,
I don't think you need delayed expansion here... although you may need it for the code represented by [...]. It is definitely what is eating your exclamation.
SETLOCAL and ENDLOCAL statements should be paired.
Try this:
Code: Select all
setlocal
[...]
:some_subroutine
md %1\new_dir
for /f "tokens=*" %%i in ('dir "%1" /b') do (
if "%%~ni" neq "new_dir" move "%1\%%i" "%1\new_dir"
)
goto :eof
endlocal
See my recent post on 'SETLOCAL ENABLEDELAYEDEXPANSION' a few posts down.
If it turns out that you need delayed expansion for [...] then do this:
setlocal enabledelayedexpansion
[...]
endlocal
:some_subroutine
setlocal
md %1\new_dir
for /f "tokens=*" %%i in ('dir "%1" /b') do (
if "%%~ni" neq "new_dir" move "%1\%%i" "%1\new_dir"
)
endlocal
goto :eof
Last edited by RG (05 May 2010 03:58)
Windows Shell Scripting and InstallShield
----------------------------
#3 05 May 2010 12:25
Mrk
Thanks for your reply RG
The code I've submitted here is simplified version of one of several "functions" in my script where this exclamation issue afflicts me.
This one indeed does not need enabledelayedexpansion and I'm actually using endlocal method within "some_subroutine", but...
...I already have too many places ("some_subroutines") where I have to turn off delayedexpansion; some of them are nested; in general enabledelayedexpansion is a must in my script and playing with a vast amount of endlocals disableng and enabling delayedexpansion is rather awkward;
I hoped to hear that I have missed some kind of syntax trick which will allow me to solve this problem in shorter and more neat way - but I am afraid you have just deprived me of this delusion :]
Thanks again for your help
Last edited by Mrk (05 May 2010 13:51)
----------------------------
#4 05 May 2010 19:15
bluesxman
Exclamation marks you want to keep are always a pain to handle with delayed expansion enabled. I'm afraid there are no easy answers to this one.
In your limited example, you could simply do this, as intimated by RG:
Code: Select all
:some_subroutine
setlocal disabledelayedexpansion
md %1\new_dir
for /f "tokens=*" %%i in ('dir "%1" /b') do (
if "%%~ni" neq "new_dir" move "%1\%%i" "%1\new_dir"
)
endlocal
goto :eof
After years using of delayed expansion liberally I finally concluded that, useful though it is, it should be used sparingly, only when absolutely necessary and with great care. You can largely (though not entirely) remove the need for delayed expansion by simply using the "call" trick.
For example:
Code: Select all
@echo off
for %%a in (*) do (
set "file=%%a"
call set "file=%%file:x=y%%"
call echo "%%file%%"
)
pause
----------------------------
#5 14 May 2010 04:21
NDog
I hope you don't mind me posting on to the end of this topic but I am having the same issue and cant seem to get around it.. I have pasted the whole code here, since its not that long.
Basically it syncs 2 folder ROOT's
I use it at an Internet cafe in town I go to, they are hosting a whole host of Asian tv shows on their server, I simply create the folder I want manually in my destination ROOT (must be the same name as on the server) and then the script scans the folder names and if they exist in both areas - copy across - ... It also writes to a log file so I don't re copy existing stuff..
So the problem is - if folders with !!! exist they don't get copied over... How would I feed this sub routine into my script?
Code: Select all
@echo off
setlocal enabledelayedexpansion
rem set _srceROOT=\\Server\movies (f)\TV - Korean 1
rem set _destROOT=%~dp0
set _srceROOT=E:\vids
set _destROOT=F:\Video\Drama\Korea
REM Scan for Existing folders in the dest (excluding hidden)
for /f "tokens=*" %%g in ('dir/b/ad-h "%_destROOT%"') do (
set _dest=%%g
REM Scan for Existing folders in the source (excluding hidden)
for /f "tokens=*" %%h in ('dir/b/ad-h "%_srceROOT%"') do (
set _srce=%%h
if "!_dest!" == "!_srce!" (
REM Start the transfer
echo ==================
echo !_srce!
echo ==================
if not exist "%_destROOT%\!_dest!\copied.txt" echo.>>"%_destROOT%\!_dest!\copied.txt"
for /f "tokens=*" %%g in ('dir /b "%_srceROOT%\!_srce!" 2^>nul') do (
for /f "usebackq tokens=1* delims==" %%h in ("%_destROOT%\!_dest!\copied.txt") do (
if "%%g" == "%%h" set _nocopy=1
)
if not defined _nocopy xcopy "%_srceROOT%\!_srce!\%%g" "%_destROOT%\!_dest!\" /f/v/y/z && echo %%g>>"%_destROOT%\!_dest!\copied.txt"
set _nocopy=
)
)
)
)
echo ==================
echo Finished...
echo ==================
echo & start /min sndrec32 /play /close %windir%\media\ding.wav
pause>nul
exit
REM Unused copy switches
rem fsync "%_srceROOT%\!_srce!" "%_destROOT%\!_dest!" /k /f /c
rem if not defined _nocopy echo %%g & copy /v/y/z "%_srceROOT%\!_srce!\%%g" "%_destROOT%\!_dest!\" && echo %%g>>"%_destROOT%\!_dest!\copied.txt"
rem if not defined _nocopy xcopy "%_srceROOT%\!_srce!\%%g" "%_destROOT%\!_dest!\" /f/v/y/z && echo %%g>>"%_destROOT%\!_dest!\copied.txt"
autoit, python, swift
----------------------------
#6 14 May 2010 10:07
bluesxman
Delayed expansion is screwing you, but perhaps you already knew that. To be frank, I see no need to be using it in that script. I propose the following simplification to your FOR commands:
Code: Select all
REM Scan for Existing folders in the dest (excluding hidden) -- token %%D
for /f "tokens=*" %%D in ('dir/b/ad-h "%_destROOT%"') do (
REM Scan for Existing folders in the source (excluding hidden) -- token %%S
for /f "tokens=*" %%S in ('dir/b/ad-h "%_srceROOT%"') do (
if "%%D" == "%%S" (
REM Start the transfer
echo ==================
echo %%S
echo ==================
if not exist "%_destROOT%\%%D\copied.txt" echo.>>"%_destROOT%\%%D\copied.txt"
for /f "tokens=*" %%D in ('dir /b "%_srceROOT%\%%S" 2^>nul') do (
for /f "usebackq tokens=1* delims==" %%S in ("%_destROOT%\%%D\copied.txt") do (
if "%%D" == "%%S" set _nocopy=1
)
if not defined _nocopy xcopy "%_srceROOT%\%%S\%%D" "%_destROOT%\%%D\" /f/v/y/z && echo %%D>>"%_destROOT%\%%D\copied.txt"
set _nocopy=
)
)
)
)
Obviously this is untested smile
cmd | *sh | ruby | chef
----------------------------
#7 16 May 2010 05:03
NDog
Thanks bluexman you saved the day again .. I didnt realise that the %% variables would be active since it was one big /for loop. Now I am confused to why we ever need !type variables, but I saw RG has written a article viewtopic.php?f=2&t=27. Im gonna read it now
Last edited by NDog (16 May 2010 05:08)
cmd, vbs, ps, bash
autoit, python, swift
----------------------------
#8 14 Jul 2010 22:31
Crash&Burn
I rarely ever see the need for ENABLEDELAYEDEXPANSION. When I was first cutting my teeth on cmd batch I used it liberally since SET's within ( ) code blocks aren't visible until you get outside the code block. Yet that usage is easily handled by using a CALL:_Some_Function "%%A" -- within a for loop. As well many FOR loops can be easily replaced with parsing the individual %1 args + SHIFT & GOTO.
I also find it better practice to do:
SET someVar="%someValue%"
vs.
SET "someVar=%someValue%"
The former generally handles all special chars that might be within a given string without needing exceptions to replace them at the start and reinsert them at the end.