1

Not quite sure how to title my issue that I'm running into (tried as best I could), but what I'm having issues with is when I'm trying to read in file names and then use them in a backup script I've wrote. I had originally tested it on files without &'s in the name (didn't remember that I had any with them in it, and didn't realize that there would be an issue until now).

Here is part of the code that is being used upto the call in the below example:

:backup2
if %DEBUG%=="t" echo Begin backup part 2
for %%? in ("!FILEREADIN!") do (
SET "FILENAME=%%~n?%%~x?"
SET "BACKUPFQP=%%~f?"
SET "BACKUPLAST=%%~t?"
call :getlength FILELENGTH "!FILENAME!"

Anyway the part that I'm running into the issue with when I'm working with the file name in my code to get the length of the file name (used in a separate section of script).

:getlength
SETLOCAL enabledelayedexpansion
if %DEBUG%=="t" echo %2 parsed... %%2 delayed... !%2!
SET "LENGTH=!%1!"
SET "STRING=%2"
REM need to correct the string for the "" that get added from passing in %2
REM Issue arises with this part below when working on a file name with a &
SET "STRING=!STRING:~1,-1!"
:getlengthwhile
if %DEBUG%=="t" echo Length !LENGTH!
if %DEBUG%=="t" echo String left:   !STRING!
SET /a "LENGTH+=1"
REM Issue here too when working with file names with &'s
SET "STRING=%STRING:~1%"
if %DEBUG%=="t" echo Length now !LENGTH!
if %DEBUG%=="t" echo String now left:   !STRING!
if %DEBUG%=="t" pause
if not ["%STRING%"]==[""] (
if %DEBUG%=="t" echo Continuing source length calculation
Goto :getlengthwhile
) else (
if %DEBUG%=="t" echo Length calculated)
ENDLOCAL & SET TEMPNUM=%LENGTH%
SET "%~1=%TEMPNUM%"
if %DEBUG%=="t" echo !%1!
if %DEBUG%=="t" pause
goto :eof

I know that there is escaping &'s to normally not have the error of the batch script trying to use the stuff right of the & as a command, but when reading in a file with one (or more) in its name how do I get it to work properly?

Here's an example of a file name that I'm having issue with and what happens when I'm running my script:

File "E:\Projects\.\Abilities&Events.docx"
Press any key to continue . . .
Begin backup part 2
"Abilities&Events.docx" parsed... %2 delayed...
'Events.docx""' is not recognized as an internal or external command, operable program or batch file.
  • With quotes around the variables. And use delayed expansion – jeb Sep 09 '16 at 13:03
  • That won't work. I've already got delayed expansion, and I can't have the quotes around the variable to get the proper length. There is also the issue later on that when I try and copy the file over it gives me error like so "is not recognized as an internal or external command, operable program or batch file." – Thomas Morse Sep 09 '16 at 13:06
  • Off topic, but you really should think about using Powershell. – Sean Sep 09 '16 at 13:31
  • Way different from batch, and I'm not looking to learn another language that I'm most likely not going to use much. :S – Thomas Morse Sep 09 '16 at 13:36
  • 1
    @ThomasMorse, plenty of perfectly good string length function written in batch if you just Google search. http://www.dostips.com/DtCodeCmdLib.php#Function.strLen – Squashman Sep 09 '16 at 14:31
  • I unfortunately really suck at researching stuff, as I know what I want to do, but not how to put it into words that can find something to help me guide myself on how to do what I want. – Thomas Morse Sep 09 '16 at 16:11
  • [Debugging your batch files](http://www.robvanderwoude.com/battech_debugging.php) – DavidPostill Sep 10 '16 at 14:06

2 Answers2

1

As said, you should use more quotes and more delayed expansion.
Btw. Your code add the length to the variable in %1, perhaps this was intended, else you should change SET "LENGTH=!%1!" to set LENGTH=0

:getlength

SETLOCAL Enabledelayedexpansion
SET "LENGTH=!%1!"
SET "STRING=%~2"

:getlengthwhile
if defined STRING (
    set /a LENGTH+=1
    set "string=!string:~0,-1!"
    goto :getlengthwhile
)
echo !LENGTH!
(
    ENDLOCAL
    SET "%~1=%LENGTH%"
)
goto :eof

Another problem of your code is this line

call :getlength FILELENGTH "!FILENAME!"

It fails with filenames containing ^, as they are doubled by the CALL.
So it's better to use

call :getlength FILELENGTH FILENAME

...

:getlength    
SETLOCAL Enabledelayedexpansion
SET "LENGTH=!%1!"
SET "STRING=!%2!"

For much faster strlen functions you could look at SO: How do you get the string length in a batch file?

Community
  • 1
  • 1
jeb
  • 78,592
  • 17
  • 171
  • 225
  • Thanks for your time, but I actually found a way to do my backup script better instead of having to get the length of the filename to do stuff later on in it. I ended up finding that I can replace parts of a string (which can be used to also delete parts of them by using something like this: `SET FILETESTPART=!FILEREADIN! if %DEBUG%=="t" echo !FILETESTPART! SET "FILETESTPART=!FILETESTPART:%SOURCE%=!" if %DEBUG%=="t" echo Filename after "!FILETESTPART!" SET "FILETESTPART=!FILETESTPART:~3!" if %DEBUG%=="t" echo Filename after "!FILETESTPART!"` – Thomas Morse Sep 09 '16 at 15:31
  • I'm still a newbie with writing batch programs, but I do see how that works better. – Thomas Morse Sep 09 '16 at 15:43
0

I found an answer to my problem. Thanks all for the help.

My solution was after finding out that I can replace parts of a variable (which I can use to delete parts of them even) from this site: http://ss64.com/nt/syntax-replace.html

I didn't know that replacing could be done (I knew that getting a part of a variable was possible (site for reference: http://ss64.com/nt/syntax-substring.html"))

I ended up ditching my getlength function (since it was no longer needed). and ended up with something like this:

:backup2
if %DEBUG%=="t" echo Begin backup part 2
for %%? in ("!FILEREADIN!") do (
SET "FILENAME=%%~n?%%~x?"
SET "BACKUPFQP=%%~f?"
SET "BACKUPLAST=%%~t?"
if %DEBUG%=="t" echo Filename before "!FILENAME!"
SET FILETESTPART=!FILEREADIN!
if %DEBUG%=="t" echo !FILETESTPART!
SET "FILETESTPART=!FILETESTPART:%SOURCE%=!" 
if %DEBUG%=="t" echo Filename after "!FILETESTPART!"
SET "FILETESTPART=!FILETESTPART:~3!"
if %DEBUG%=="t" echo Filename after "!FILETESTPART!"