I know there are already a few questions here about this same issue but I am new to batch scripting and I found those solutions hard to apply in my scenario or directly not applying to my script.
A solution seems to be to temporarily disable DelayedExpansion
but if I do so then nothing works anymore.
What the script below is trying to accomplish and it works except for the paths with !
, is the following:
It will take a source folder and file by file, including subfolders, check if the file exists in a destination folder. If the file does not exist then it can do two things:
- Copy the file from the source folder to the destination folder, if it is a png, jpg or mp4
- Create a dummy file (a 0 bytes file with the same name and extension) in the destination folder if it is not a
.png
,.jpg
or.mp4
. I use for this xcopy (I copy an existing zero bytes file and rename it) because it is the only way I had no issues with special characters.
@echo off
setlocal EnableExtensions EnableDelayedExpansion
rem Set the source and destination folders
set "src=L:\folderS\sub1\sub2"
set "dst=L:\folderD\sub1"
rem Set the path to the dummy file that we need to create dummy files with xcopy
set "dummy=L:\dummy.txt"
rem Create the destination folder if it doesn't exist
if not exist "%dst%" mkdir "%dst%"
rem Loop through all the files in the source folder
for /R "%src%" %%f in (*) do (
rem Get the file path
set "filePath=%%f"
echo the full path is !filePath!
rem Get the file extension
set "ext=%%~xf"
rem Get the relative path excluding the path until the specified src folder
set "relPath=!filePath:%src%\=!"
echo the relative path is !relPath!
rem Check if the file does not exist in the destination
if not exist "%dst%\!relPath!" (
rem Check if the file extension is png jpg or mp4
if /I "!ext!" == ".png" (
rem If the file extension is png jpg or mp4 copy the file and display a message
rem echo Copying "%%f" to "%dst%\!relPath!"
xcopy /y "%%f" "%dst%\!relPath!*"
)else if /I "!ext!" == ".jpg" (
xcopy /y "%%f" "%dst%\!relPath!*"
)else if /I "!ext!" == ".mp4" (
xcopy /y "%%f" "%dst%\!relPath!*"
)else (
rem If the file extension is not png jpg or mp4, create a dummy file
echo Creating dummy "%%f" to "%dst%\!relPath!"
xcopy /y "%dummy%" "%dst%\!relPath!*"
)
)
)
echo Done.
The problem seems to be when I store the relative path to the file in relPath, if the filename or any of the subfolders contains a !
then it will ignore everything that goes after the !
but still keeps the file extension somehow. I think, but I am not sure, that even if I would manage to store correctly the path in relPath, I would still have issues when using later on "%dst%\!relPath!"
in the other parts of the for loop for copying the file or checking if it exists.
How could I get around this?
EDIT: Here is an screenshot showing the result for a very simple scenario:
EDIT 2: I tried now with @harrymc suggestion and it seems to have solved partially the issue but some filenames are still giving trouble. New code:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
rem Set the source and destination folders
set "src=L:\folderS\sub1\sub2"
set "dst=L:\folderD\sub1"
rem Set the path to the dummy file that we need to create dummy files with xcopy
set "dummy=L:\dummy.txt"
rem Create the destination folder if it doesn't exist
if not exist "%dst%" mkdir "%dst%"
rem Loop through all the files in the source folder
for /R "%src%" %%f in (*) do (
rem Get the file path
set "filePath=%%f"
echo the full path is !filePath!
rem Get the file extension
set "ext=%%~xf"
setlocal EnableExtensions EnableDelayedExpansion
rem Get the relative path excluding the path until the specified src folder
set "relPath=!filePath:%src%\=!"
echo the relative path is !relPath!
rem Check if the file does not exist in the destination
if not exist "%dst%\!relPath!" (
rem Check if the file extension is png jpg or mp4
if /I "!ext!" == ".png" (
rem If the file extension is png jpg or mp4 copy the file and display a message
rem echo Copying "%%f" to "%dst%\!relPath!"
xcopy /y "%%f" "%dst%\!relPath!*"
)else if /I "!ext!" == ".jpg" (
xcopy /y "%%f" "%dst%\!relPath!*"
)else if /I "!ext!" == ".mp4" (
xcopy /y "%%f" "%dst%\!relPath!*"
)else (
rem If the file extension is not png jpg or mp4, create a dummy file
echo Creating dummy "%%f" to "%dst%\!relPath!"
xcopy /y "%dummy%" "%dst%\!relPath!*"
)
)
endlocal
)
echo Done.
Here is an example of a filename that still give trouble. I think now this is xcopy limitation due to the length of the filename or maybe another symbol.
EDIT 3: It is fully solved now. The last remaining problem was with the lines
xcopy /y "%%f" "%dst%\!relPath!*"
that should instead be:
echo F|xcopy "!filePath!" "%dst%\!relPath!"
this fixed the problem I was still having with some symbols, and with the "F|" xcopy will not ask me each time if it is a file or not. There is still probably the limitation of 256 chars for xcopy but I don't see to hit that limit. I could instead use robocopy which would be better but robocopy parameters are quite different and I would need probably quite a few attempts to get it right.
Thank you everyone!
X
' but I want isY
setlocal EnableExtensions DisableDelayedExpansion
and use percent characters, not exclamation marks.