Copy "can't find file specified" in nested for loop - batch-file

Copying works fine everywhere else in the program, only seems to mess up inside this nested for loop. Returning "The system cannot find the file specified." (I assume that is the first non-switch argument passed to copy)
Running windows 10,
delayedexpansion IS enabled
Further up in the program I am grabbing .pdf files from a scanning folder, creating a copy in both output and done directories. Later I realized that I needed some type of continuity check to make sure that the files in output were correct (Originally "done" was just used to not re-copy files I had already moved out of the "output" folder). Every pass of the program the "done" folder gets updated with the scanned files (sometimes a file is still getting loaded in from the scanner and gets partially copied).
Tried changing what I give copy in terms of file "%%~nxA" was one of them
SET useableDirectory="C:\Users\IoCalisto\Desktop\custom scan filter\output"
FOR /R "C:\Users\IoCalisto\Desktop\custom scan filter\done" %%A in (*.pdf) do (
IF EXIST "C:\Users\IoCalisto\Desktop\custom scan filter\output\%%~nxA" (
SET useableFile="C:\Users\IoCalisto\Desktop\custom scan filter\output\%%~nxA"
FOR %%B in (!useableFile!) do (
echo File: %%~zB check: %%~zA
IF %%~zA EQU %%~zB echo FILE SIZE CORRECT
IF %%~zA GTR %%~zB (
copy %%A %useableDirectory%
echo %%A
echo %%~nxA
echo !useableFile!
echo %useableDirectory%
)
IF %%~zA LSS %%~zB echo FILE SIZE ERROR, CORRECTING IN NEXT PASS?
echo.
)
)
)
This section of the program is a part of an integrity check to make sure files are complete. The "C:\Users\IoCalisto\Desktop\custom scan filter\done" directory has complete files, and I only want to copy over files that have fewer bits in the output directory. I would like to stay away from just copying everything over from the done folder, because I see this as a learning opportunity.
EDIT: the error happens if the "IF %%~zA GTR %%~zB" conditional is true. The first thing inside the body of the IF statement, is a copy command. The output from this command is in between two echo statements that both work as intended (first is outside the conditional and simply lists the file sizes).
(see attached)

Related

Concatenated text file output from single ECHO command gets characters inserted into string printed a second time after expected output

I'm trying to create a batch file to insert a string from a .txt file at a specific place inside a string in 225 batch files - i.e., inserted into one line in the file at a specific place - but this question concerns the inserting part, and not the loop part, so I've left out the latter in my code example. It's also currently just displaying the text on-screen; not actually writing it to files.
The target files are a bunch of launch .bat files used for running a game server cluster using a tool, so I will have to leave each of them with the same names as they start with (Start XXYY.bat). They contain something along these lines:
start /high ShooterGame\Binaries\Win64\ShooterGameServer.exe Ocean?ServerX=0?ServerY=0?AltSaveDirectoryName=0000?ServerAdminPassword=1234?MaxPlayers=50?ReservedPlayerSlots=25?QueryPort=50002?Port=5002?SeamlessIP=192.168.1.225?RCONEnabled=true?RCONPort=28450 -log -server -NoBattlEye
exit
Where the ServerX, ServerY, AltSaveDirectoryNamen and all three Port settings are unique to each server, so these will have to remain unchanged.
I need to add several more settings, from another .txt file in the final version, but for this example I will just put the additions (the word INSERT added after the ReservedPlayerSlots setting, while keeping each setting divided by question marks) directly into this script.
My code is actually doing exactly what I want it to, but unfortunately it doesn't stop at that point, and decides to append more text than I wanted; specifically, everything I add to the ECHO command which is not a variable name.
To clarify, I get the exact output that I want... Plus the unwanted addition of a bunch of question marks and the word INSERT, which apparently come from my ECHO command, but I just have no idea why they get re-added.
My knowledge of batch scripting is fairly limited, so there might well be something basic that I've overlooked.
I've tried replacing the question marks in the output (which are required to be questions marks in the final version) with normal letters instead, but it doesn't change the behaviour; they were still appended to the expected output, just like the question marks they replaced.
#ECHO OFF
SET FileNum=0000
REM I will have the code loop through 225 files (0000-1414) in the final version, but for test purposes I just set it to one single file number manually here.
SET FileName=Start %FileNum%.bat
REN "%FileName%" temp.txt
FOR /F "tokens=1,2,3,4,5,6,7,8,9,10,11,12 delims=?" %%a IN (temp.txt) DO (
ECHO %%a?%%b?%%c?%%d?%%e?%%f?%%g?INSERT?%%h?%%i?%%j?%%k?%%l
)
REN temp.txt "%FileName%"
I expect this code to output this:
start /high ShooterGame\Binaries\Win64\ShooterGameServer.exe Ocean?ServerX=0?ServerY=0?AltSaveDirectoryName=0000?ServerAdminPassword=1234?MaxPlayers=50?ReservedPlayerSlots=25?INSERT?QueryPort=50002?Port=5002?SeamlessIP=192.168.1.225?RCONEnabled=true?RCONPort=28450 -log -server -NoBattlEye
exit
But what I am getting is this:
start /high ShooterGame\Binaries\Win64\ShooterGameServer.exe Ocean?ServerX=0?ServerY=0?AltSaveDirectoryName=0000?ServerAdminPassword=1234?MaxPlayers=50?ReservedPlayerSlots=25?INSERT?QueryPort=50002?Port=5002?SeamlessIP=192.168.1.225?RCONEnabled=true?RCONPort=28450 -log -server -NoBattlEye
exit???????INSERT?????
Which is the expected output, but with the unexpected re-addition of every symbol in the ECHO command which did not designate a variable at the end of the output (in this case ???????INSERT?????), just after the exit.
I'm stumped... I hope someone has an idea what I'm doing wrong here.
Okay, I applied the idea that aschipfl provided, and it seems to work now.
The IF NOT "%%b"=="" line seems to have done the trick, after I added the final line with the exit using another ECHO. My full script (including loop and write to file) is now like this:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
SET "Insert=SettingOne=True?SettingTwo=False?SettingThree=1.000000"
FOR /l %%x IN (0, 1, 14) DO (
FOR /l %%y IN (0, 1, 14) DO (
IF %%x LSS 10 (SET XNum=0%%x) ELSE (SET XNum=%%x)
IF %%y LSS 10 (SET YNum=0%%y) ELSE (SET Ynum=%%y)
SET "FileNum=!XNum!!YNum!"
SET "FileName=Start !FileNum!.bat"
ECHO Filename: !FileName!
REN "!FileName!" temp.txt
(
FOR /F "tokens=1-12 delims=?" %%a IN (temp.txt) DO (
IF NOT "%%b"=="" (
ECHO %%a?%%b?%%c?%%d?%%e?%%f?%%g?%Insert%?%%h?%%i?%%j?%%k?%%l
ECHO exit
)
)
) >edited.txt
REN edited.txt "!FileName!"
DEL /q temp.txt
ECHO has been updated
)
)
This is now working exactly as intended.
It's quite possible that there is a more elegant way of doing this, and I am cartain that there is a way of making this more general and less hard-coded, but it's good enough for my purposes.
I thank you for your help!

Batch file - output csv to different folders

everything in my code is working fine except the last part.
I am wanting to output each text file to the folder with the same name. It is outputing the three text files into the one folder PentahoOutputs. However I am wanting to output it as the following:
folder system2.object2.assets contains file system2.object2.assets
folder system3.object3.assets contains file system3.object3.assets
folder system4.object4.assets contains file system4.object4.assets
#echo off SetLocal EnableDelayedExpansion
SET DELIMS=,
SET COMMAND=AddChange
SET EN=EN
SET ASSETS=Assets
SET DIREC = C:\Users\user.username\Documents\Training\BatchFiles\PentahoOutputs\
SET DELIMS2=.
FOR /D %%a IN (C:\Users\user.username\Documents\Training\BatchFiles\PentahoOutputs\*) DO ( SET subdirs=%%a
result=!subdirs:~71,7!
result2=!subdirs:~79,7!
set "concats=!result!!delims!!result2!!DELIMS!!COMMAND!!DELIMS!!EN!"
echo !concats!
echo !CONCATS! >>C:\Users\user.username\Documents\Training\BatchFiles\PentahoOutputs\!result!!delims2!!result2!!delims2!!assets!.CSV
)
PAUSE>NUL
edit ********** below
changing the problem code to the following puts each of the three files in each of the three folders... however i want one file in each folder
for /d %%b in (C:\Users\usre.username\Documents\Training\BatchFiles\PentahoOutputs\*) DO ( echo !CONCATS! >>%%b\!result!!delims2!!result2!!delims2!!assets!.csv )
From your posted code - given aschipfl's change as noted (although you don't attempt to use direc)
Your posted code has been mangled in an attempt, I assume, to disguise usernames. It also appears that you've cut down the actual code to show only the relevant section. This is good and understandable (but your edit has a glaring typo in the code - which is why you should cut-and-paste as far as possible.)
So - the setlocal following the #echo off must be separated by a & command-concatenator or be (my preference) on a separate line.
Within your for ... %%a ... block, you've removed the required set keyword for result*.
The fixed values you've used for substringing don't suit the changes you've made to the pathname, so the result in result is (eg) "tem3.ob"
If a value does not change within a block (like delims) then it's probably best to use %delims% - result changes, so you'd use !result! not %result%. !delims! also works, of course - but using the delayed-expansion form primes the reader to believe it's going to vary. (opinion)
'tis best with a string assignment to use set "var=value" as the quotes ensure that stray trailing spaces are not included in the value assigned. You only ever need to have that happen once...
OK - here's a revision
#echo OFF
SetLocal
SET DELIMS=,
SET COMMAND=AddChange
SET EN=EN
SET ASSETS=Assets
SET DIREC=U:\Users\user.username\Documents\Training\BatchFiles\PentahoOutputs\
SET DELIMS2=.
FOR /D %%a IN (%direc%*) DO (
FOR /f "tokens=1,2,3 delims=." %%p IN ("%%~nxa") DO IF /i "%%r"=="%assets%" (
echo %%p%delims%%%q%DELIMS%%COMMAND%%DELIMS%%EN%
echo %%p%delims%%%q%DELIMS%%COMMAND%%DELIMS%%EN% >> %%a\%%~na.CSV
)
)
GOTO :EOF
Note that I've used U: for the test directory (it's a ramdrive on my machine)
Given the outer loop, %%a is assigned the full pathname to the directory.
Since you imply that your target directorynames are system2.object2.assets then %%~nxa (the Name and eXtension of %%a) conveniently holds this string. Parsing that using delims of . and selecting the first 3 tokens would assign system2 to %%p, object2 to %%q and assets to %%r This avoids the substringing problem and permits system and object to be any length - not just 7.
The if statement ensures that the main block for for...%%p is only executed for directories found which fit ..asset (/i makes the if case-insensitive)
The required line can then be constructed from the metavariables and constants, as can the destination filename, so the enabledelayedexpansion is not required.

Batch Code Win7 Outputing to file doesnt work but appending it does?

So im working on a batch file that can Extract certain lines of text from a massive number of txt files. I had it working fine inside 1 folder but I needed it to be recursive so I changed it up a bit, and It no longer Outputs anything to a text file
for /r %%Z in (*.as) do (
SET /a count=0
set /a non_eng=0
echo z = %%Z
pause
for /F "eol=; tokens=1,2 usebackq delims=(" %%A in ("%%Z") do (
set /a count+=1
if /i %%A==texte echo !count!=%%A(%%B
) > "%%Z.txt"
Echo Writting To File %%Z.txt
pause
if exist "%%Z" echo LC_!count! >> "%%Z.txt")
This Line No longer works
) > "%%Z.txt"
But if I change it to >> it works fine... Problem Is it doubles up the copied text each time...
Working version (just doesn't delve into directories)
PS: I Worked around this issue but Im still unsure as to what caused the problem in the first place at the very least I believe I should have been geting at least one line of correct output to the file.
Your working code has the redirection placed at the for loop that iterate the files, not the for /f that reads them. In this way there is one open/write/close on the log file for each file being processed, with all the data echoed inside redirected to the output file.
But in the non working version, you have the redirection at the for /f that reads the files. Now you have a open/write/close operation for each of the lines of the file being processed. And, as the redirection is >, only the last execution of the for /f is saved in the file.
The simplest way to avoid it is to enclose the inner for loop in parenthesis and redirect this block
(
for /f .... %%A in (...) do (
....
)
) > "%%Z.txt"

Trying to write a calling batch file but keep getting "cannot find" error

I am trying to write a batch file that calls another which replaces two files in a directory. Here is my code:
set mmcIpath="C:"*"\mmc-stable-win32\MultiMC\instances"
call C:\%mmcIpath%\spc_we_replace_CED+CEDU.bat
Whenever I set the temporary environment variable, it says the directory cannot be found.
--ADDITIONAL INFO--
I run a Minecraft launcher called MultiMC5; it has a feature which runs commands - but only one command, for some reason. So I wanted it to call a batch file to run multiple commands.
My main batch file is in "C:...\MultiMC\instances", but I want the program to be able to call it. It cannot, as it works within a subdirectory called "CED (210 mods-)". So I placed another batch in the subdirectory to call the main one (I wanted to do the same for a second subdirectory called "CEDU (300+ mods-)"). I got this error: "The system cannot find the path specified.". It happened when I set the path.
I'm using Windows 8.1 and have searched for tips on how to use wildcards and on how to use FOR loops, but none of the wildcard methods have worked for me and I cannot understand FOR loops at all. I have also tried to remove and add things like quotation marks in an attempt to fix it, but that didn't work either.
My question:
Is the set command compatible with wildcards and if so, how do I get this to work?
It looks like your problem is that the main batch file can be on any drive and you want to call other batch files with a path relative to the location of main batch file. Is that correct?
You can get the drive with %~d0, path with %~p0 and drive + path with %~dp0. See the example below and execute this little batch file stored in several different directories:
#echo off
echo Batch is stored on drive %~d0
echo in the directory %~p0
echo resulting in path %~dp0
So you can use argument 0 referenced by %0 containing always name of batch file with full path using the syntax above explained in help of command FOR displayed with entering for /?in a command prompt window to call the other batch files with a path depending on path of the main batch file.
Now what we have here is a classic XY problem - being asked about a solution, not the underlying issue.
Here's a possible resolution:
#ECHO OFF
SETLOCAL
set mmcIpath="C:"*"\mmc-stable-win32\MultiMC\instances"
set "mmcIpath=U:\\.*\\mmc-stable-win32\\MultiMC\\instances"
SET "targetbat=spc_we_replace.bat"
FOR /f "delims=" %%a IN (
'dir /b/s /ad "%mmcIpath:~0,3%"^|findstr /e /i /r /c:"%mmcIpath%" '
) DO (
IF EXIST "%%a\%targetbat%" (
ECHO CALL "%%a\%targetbat%"
ECHO GOTO nextstep
)
)
:nextstep
GOTO :EOF
I've left the original setting of mmcIpath in place, and replaced it with a form to suit my system.
The approach is to execute a dir/s/b/ad command (directory, basic format, with subdirectories, directory names only) and filter it using findstr. I chose switches /i (case-insensitive) /e (must end with string) /r regular-expression /c: (following is one string to be matched).
The regex is constructed according to findstr's rules - \ needs to be doubled if it is to be used as a literal; .* means 'any number of any character'
This should provide a list of literal directory names which get through the filter. Look in the directory found for the filename, call the target file if found. The required CALL commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO CALL to CALL to actually execute the files.
The following ECHO GOTO is there to show that the loop can be broken after finding the first target file, if desired. You havent't indicated whether you want to run only the first or run all of the targets found.
Here's my test source. I use U: for testing data. Your system would likely be different.
#ECHO OFF
SETLOCAL
SETLOCAL ENABLEDELAYEDEXPANSION
set "mmcIpath=\mmc-stable-win32\MultiMC\instances"
FOR /l %%a IN (1,1,4) DO MD u:\%%a%mmcIpath% 2>nul
FOR /l %%a IN (2,2,4) DO COPY NUL u:\%%a%mmcIpath%\spc_we_replace.bat 2>NUL >nul
ENDLOCAL
ENDLOCAL
#ECHO OFF
SETLOCAL
set mmcIpath="C:"*"\mmc-stable-win32\MultiMC\instances"
set "mmcIpath=U:\\.*\\mmc-stable-win32\\MultiMC\\instances"
SET "targetbat=spc_we_replace.bat"
FOR /f "delims=" %%a IN (
'dir /b/s /ad "%mmcIpath:~0,3%"^|findstr /e /i /r /c:"%mmcIpath%" '
) DO (
IF EXIST "%%a\%targetbat%" (
ECHO CALL "%%a\%targetbat%"
ECHO GOTO nextstep
)
)
:nextstep
GOTO :EOF
Note that the first section is merely establishing u:\1\mmc-stable-win32\MultiMC\instances to u:\4\mmc-stable-win32\MultiMC\instances then creating a dummy file spc_we_replace.bat in u:\2\mmc-stable-win32\MultiMC\instances and u:\4\mmc-stable-win32\MultiMC\instances.
The string assigned to mmcIath in the second section is according to findstr's syntax rules - each \ is doubled, .* means "any number of any character". You would have to modify that string to suit your system. Note that "%mmcIpath:~0,3%" gratuitously takes the first 3 characters from the string. In my case, that would be U:\. YMMV

batch file script to backup old increment of multiple files and change the last increment to "1"

First of all, I am completely newbie here in batch file scripting and willing to learn it.
Let's say that I have a bunch of files in a folder with file extension/file-ext: ext1, ext2, and ext3.
every single file has incrementation such as:
filename.file-ext.1
filename.file-ext.2
filename.file-ext.3
...
filename.file-ext.x
The main target is to backup the old increments(from 1 to x-1), then backup them in a new folder, and then change the last increment "x" to "1".
Any kind of help from you would be highly appreciated.
The main problem when file names contain numbers is that they appear in alphabetic, not numeric, order. For example:
filename.file-ext.1
filename.file-ext.10
filename.file-ext.11
filename.file-ext.12
filename.file-ext.2
filename.file-ext.3
filename.file-ext.4
filename.file-ext.5
filename.file-ext.6
filename.file-ext.7
filename.file-ext.8
filename.file-ext.9
The last file in previous list should be 12, but the last name given by for or dir commands is 9. The Batch file below uses a two-pass approach: it first review the whole list and get the real last numeric file, then it process the list again and backup all files excepting the last one.
#echo off
setlocal EnableDelayedExpansion
rem First pass: Get the last numeric file
set last=0
for %%a in (filename.ext.*) do (
set num=%%~Xa
if !num:~1! gtr !last! set last=!num:~1!
)
rem Second pass: Backup all files excepting the last one
for %%a in (filename.ext.*) do (
if %%a neq filename.ext.%last% move %%a \backupDir
)
rem Rename the last file, if it is not 1
if %last% gtr 1 ren filename.ext.%last% filename.ext.1
The program above was written as simplest and clearest as possible. You must insert some quotes if file names may have spaces.
#ECHO OFF
SETLOCAL
SET filename=FILENAME
SET fileext=FILE-EXT
SET "deedpoll="
FOR /f "delims=" %%i IN ('dir /b /a-d /o:-d "%filename%.%fileext%*"') DO (
IF DEFINED deedpoll ECHO MOVE "%%i" "\newdir\" >nul
IF NOT DEFINED deedpoll SET "deedpoll=%%i"
)
IF DEFINED deedpoll ECHO REN "%deedpoll%" "%filename%.%fileext% 1"
since we have no clue as to the real filename or file extension involved, we can only assume that they will be simple alphamerics and spaces. I've also assumed that your destination directory exists and that your current directory is the one containing your fileset.
And I've assumed that your sequencing will work on DATE - it's the NEWEST file that does NOT get backed up (moved to newdir) and renamed ...1
It's quite simple. First clear deedpoll then perform a dir listing of the /b bare filename, /a-d with no directorynames /o:-d in reverse-order of date.
The first filename assigned to %%i will thus be the newest. deedpoll is not yet set, so the move is not executed, and then deedpoll is assigned the name of the newest file.
Since deedpoll is now set (or defined) then the move will be done for each of the other filenames matching the supplied mask.
finally, deedpoll is renamed to version 1.
Note that the REName and MOVE commands are merely ECHOed to the screen. This is to allow you to ensure that the batch would do what you want it to do. If all is correct, remove both of these ECHO keywords to activate the rename and move.

Resources