Execution depends on what comes AFTER the line in question????????

Microsoft Windows
Post Reply
Rekrul
Posts: 52
Joined: 2021-Aug-15, 11:29 pm

Execution depends on what comes AFTER the line in question????????

Post by Rekrul »

OK, I'm at my wits end here. I'm trying to write a script that will pack ISO images to 7zip files. As part of that process, it detects whether the filename has "(Disc " in it, then it parses the filename to create a pattern that will find all the discs in that set and also what the highest number disc is, so that it can put that information in the archive name. At least that's what it's supposed to do.

I first wrote the script to loop though multi-disc images and process them separately, then move them to a temporary directory and process everything that was left. I have that script working perfectly. However, I wanted to streamline it by simply having it detect whether the filename has "(Disc " in it and process it accordingly. That's where everything went wrong.

For some reason, the script fails on an IF comparison with an error based on the filename having something enclosed both in parenthesis and brackets. However, when I change the commands AFTER that line, no more error.

An example filename that causes a problem is;

Some Program (test) [new].iso

To simplify things, I've added the example filename right to the scripts for testing.

I can post the entire script if you want, but it's kind of long and confusing. Here's the part that doesn't work with that filename;

Code: Select all

@echo off
cls
set Name=Some Program (test) [new]
set Ext=.iso
call :Process
)

goto end

:Process
if "%Name%"=="%Name:(Disc =%" (
pause
set Pattern=%Name%
set Archive=%Name%
exit /b
)

:end
This generates the error "[new] was unexpected at this time." and the PAUSE command is never executed. However this does NOT generate an error;

Code: Select all

@echo off
cls
set Name=Some Program (test) [new]
set Ext=.iso
call :Process
)

goto end

:Process
if "%Name%"=="%Name:(Disc =%" (
pause
exit /b
)

:end
Obviously this doesn't do anything, but most importantly it doesn't generate an error! It executes PAUSE and then exits the routine.

To further confuse the issue, if I remove "(test)" from the filenames, then the "[new]" doesn't generate an error.

I'm at a complete loss for for what's going on here. Except for the parts that were changed, I literally copied and pasted the code from the script that fails to the script that doesn't fail, just to make sure that there wasn't a hidden space somewhere that I was missing.

Then I thought maybe it had to do with the two SET commands being evaluated as part of the IF command, and maybe there was a problem with them, but if I remove the IF comparison, those commands work fine.

What am I missing here? The IF comparison is EXACTLY THE SAME!!! Why does the first example generate an error with that filename, but the second doesn't?

Again, because virtually EVERY SINGLE TIME I post a code snippet, someone points out that it doesn't do anything, let me again state: This is part of a much longer script. The rest of the script is not relevant to this problem. This is the part of the script that fails and what I've posted is enough to illustrate the problem. If I can't get this one part to work, worrying about the rest of the script is pointless.
Simon_Weel
Posts: 34
Joined: 2021-Dec-13, 3:53 pm

Re: Execution depends on what comes AFTER the line in question????????

Post by Simon_Weel »

The part that fails is this:
set Pattern=%Name%
set Archive=%Name%
If you add quotes, the problem is solved:
set Pattern="%Name%"
set Archive="%Name%"

But it's weird - if you execute the script line by line (copy / paste) in the command window, it won't throw an error.

And I wonder what this does: if "%Name%"=="%Name:(Disc =%"
It seems to evaluate true always? What is the purpose of this part: :(Disc =
User avatar
Simon Sheppard
Posts: 190
Joined: 2021-Jul-10, 7:46 pm
Contact:

Re: Execution depends on what comes AFTER the line in question????????

Post by Simon Sheppard »

I think the problem here is that your filename includes a close parenthesis ')'

Unless enclosed in quotes, the CMD shell is not clever enough to realise that is part of the filename and instead acts like you are closing the parenthesis opened a couple of lines above.
Rekrul
Posts: 52
Joined: 2021-Aug-15, 11:29 pm

Re: Execution depends on what comes AFTER the line in question????????

Post by Rekrul »

Simon_Weel wrote: 2022-Oct-13, 7:43 am The part that fails is this:
set Pattern=%Name%
set Archive=%Name%
If you add quotes, the problem is solved:
set Pattern="%Name%"
set Archive="%Name%"
I suppose I can do that, I'll just have to add the extensions there instead of later. Which I don't know why I didn't do anyway, other than that I often think of assembling the final filenames in the last step. Also, I didn't realize that you can separately enclose both a path name and a filename in quotes, I thought the whole thing had to be enclosed in quotes until I just tried it.
Simon_Weel wrote: 2022-Oct-13, 7:43 amBut it's weird - if you execute the script line by line (copy / paste) in the command window, it won't throw an error.
I've run into problems trying to test things that way. In particular, you can't test for undefined/empty strings.
Simon_Weel wrote: 2022-Oct-13, 7:43 amAnd I wonder what this does: if "%Name%"=="%Name:(Disc =%"
It seems to evaluate true always? What is the purpose of this part: :(Disc =
That relates to the function of the full script, which is to pack multi-disc sets together. So for example, if you have;

A Program (mine) [new].iso
New stuff.iso
Some Program (Disc 1).iso
Some Program (Disc 2).iso
Some Program (Disc 3).iso


The script will pack A Program (mine) [new].iso and New stuff.iso each to their own archive, then it will pack the Some Program (Disc *).iso files to a single archive named Some Program (3 Discs).7z.

The IF line in the snippet I posted is meant to determine whether a file is part of a multi-disc set. If the comparison is true, it means the filename doesn't contain "(Disc " and can be packed on its own. However if the comparison fails, much more work is required to get the results that I want.

First it has to determine if it contains "(Disc 1)" or "(Disc 01)", in order to prevent it from acting on every disc in the set. In my first script, I explicitly searched for those patterns, but I wanted to make a more elegant solution, since they had to be temporarily moved to a different directory to keep the part of the script that packs single discs from packing each disc in a set separately.

Then it needs to split the filename apart so that I get the part before and after "(Disc ?)". This is done not only so that I can make a wildcard pattern that will include all the discs in the set, but also so that I can format the archive name to include the number of discs. To get the number of discs, it loops through the set with the wildcard, isolating the number and putting it into a variable, so the last value is the highest numbered disc. It then sends all this information to 7zip for packing.

My new script has some other bugs in it and doesn't quite work, beyond the part that I posted. It runs through all the discs in a multi-disc set, not just the first ones.

Thinking about it now as I type this, I believe I just came up with a better way to do it. :)

Part of my goal for rewriting the script was to make it easier to add additional file formats without having to explicitly search for the first disc in a set for each type. I should just be able to tell it what extensions to look for and have it go from there. Additionally, with a little tweaking, I should also be able to make it handle multi-disk sets of floppy disk images for emulators. Just add the new extension and the script does the rest.

Of course, the files have to have "(Disc ?)" in the filename for it to work, otherwise, they'll be treated a single discs and packed individually.
Simon Sheppard wrote: 2022-Oct-13, 6:12 pm I think the problem here is that your filename includes a close parenthesis ')'

Unless enclosed in quotes, the CMD shell is not clever enough to realise that is part of the filename and instead acts like you are closing the parenthesis opened a couple of lines above.
I guess that's it. I keep forgetting that "variables" in batch aren't real variables, but rather just placeholders.

I'd post my original script, but looking at it now, it's basically kind of a mess. When I get this script perfected, I'll come back and post it. Assuming I get it finished. I have a bad habit of getting things 75-90% finished and then losing interest. As long as it mostly works, I kind of lose my enthusiasm for perfecting it.
Rekrul
Posts: 52
Joined: 2021-Aug-15, 11:29 pm

Re: Execution depends on what comes AFTER the line in question????????

Post by Rekrul »

My script is done. No, it didn't take me this long to write it, I just kept putting it off. It only took me a couple of hours once I sat down to do it. That will probably make some people laugh as what it does isn't overly complex, but I kept making trivial mistakes and running into unforeseen problems.

This script is mainly intended for emulation users. It will pack all the ISO files in a directory to 7zip archives. It will automatically pack BIN/CUE sets together. In fact if there are any other files with the same base name (TXT, PDF, JPG, etc), they will be packed as well. If a set contains multiple discs, they will all be packed to the same archive, provided that the filenames are numbered using the Format of "(Disc xx", where "xx" is a one or two digit number or a single letter, and the names are otherwise identical up to that point. It will pack ISO files, BIN/CUE sets and ADF files, which are Amiga disk images. The filenames can use the word "Disc" or "Disk", and can also use the format of "(Disk x of x)" with either one or two digits, or a single letter. It will even work for sets of ten or more files that use a single digit for the files up to nine, even though I personally think that numbering files in that way is a horrible practice.

If there are multiple discs/disks in a set, it will count the number of discs/disks in the set and put that information in the archive name, in place of the disc/disk number. If a directory name is included on the command line, the files will be packed to that directory (if it exists), otherwise they will be packed to the same directory.

It won't detect sets of 100 or more discs/disks. I've never seen an Amiga game that had that many disks, and I can't imagine anyone wanting to pack that many ISO files together. If someone needs that, it would be trivial to add. If the filenames differ after the disc/disk number, the archive will be named according to the first file in the set. For example;

Game (Disk 1 of 2) (Boot Disk).adf
Game (Disk 2 of 2) (Game Disk).adf

The archive will be named;

Game (2 Disks) (Boot Disk).7z

I thought about just discarding the rest of the filename after the number, but decided against it as some filenames may include additional information that I want to keep.

While it can be used from the command line, it will work quite well if called from a two-pane file manager. Pass it the target directory to have it automatically pack files from one pane to the other with a single click.

Additional file formats can easily be added, just by adding them to the first FOR line. The script will process whatever types of files it's told to look for. I thought about adding more emulator formats, but didn't see a big need for it personally.

I know I'm probably the only one who will use it, but I promised to post it, so here it is. I've thought about adding a menu with some options, but for now it's done. It may not be the most elegant, but it works. :)

Code: Select all

@echo off
cls
echo.
echo.
set Dir=%~1

if "%Dir%"=="" set Dir=.\
if not "%Dir:~-1%"=="\" set Dir=%Dir%\
if not exist "%Dir%" set Dir=.\

for %%F in (*.bin *.iso *.adf) do (
set Name=%%~nF
set Extension=%%~xF
call :Process
)

goto End

:Process
if "%Name%"=="%Name:(Disc=%" (if "%Name%"=="%Name:(Disk=%" (
set Pattern="%Name%.*"
set Archive="%Name%.7z"
goto Pack
))
set Name2=%Name%
set Name2=%Name2:(Disc A=^*%
set Name2=%Name2:(Disc 1)=^*)%
set Name2=%Name2:(Disc 1 of=^* of%
set Name2=%Name2:(Disc 01=^*%
set Name2=%Name2:(Disk A=^*%
set Name2=%Name2:(Disk 1)=^*)%
set Name2=%Name2:(Disk 1 of=^* of%
set Name2=%Name2:(Disk 01=^*%
if "%Name%"=="%Name2%" exit /b
if not "%Name%"=="%Name:(Disc=%" (set Type=Disc) else (if not "%Name%"=="%Name:(Disk=%" (set Type=Disk))
for /f "tokens=1,2 delims=*" %%A in ("%Name2%") do (
set Part1=%%A
set Part2=%%B
)
if "%Part2:~1,3%"=="of " set Part2=)%part2:*)=%
set Pattern="%Part1%*.*"
set Pattern2="%Part1%*%Extension%"
set X=0
for %%C in (%Pattern2%) do set /a X=X+1
set Archive="%Part1%(%X% %Type%s%Part2%.7z"

:Pack
echo Packing %Archive%
7z a -bso0 -mx9 "%Dir%"%Archive% %Pattern%
exit /b

:End
Post Reply