Batch file renames files incorrectly - windows

I am using an executable file (called reduce.exe) to use two functions on PDB files and rename them once done, and am trying to do this to an entire file directory. I have a text file named pdblist.txt that sits right next to the batch file. My current file looks like this:
setlocal enabledelayedexpansion
echo off
for /F %%g in (pdblist.txt) do (
set var=!%%g:~0,4!
echo !var!
set trim=!var!no_H.pdb
echo !trim!
set build=!var!h.pdb
echo !build!
reduce.exe -Trim %%g > !trim!
reduce.exe -BUILD !trim! > !build!
)
However, when I run the batch file, it creates two files, called "~0,4h.pdb" and "~0,4no_H.pdb". I am supposed to end up with three files for each original file name, as in this example:
Original file name is 1csl.pdb, after the Trim function, it creates 1csl_noH.pdb, and after the BUILD function, it creates 1cslh.pdb
So, could you please explain why it is not creating two more files? Are the exclamation points in the wrong places on the set var line, or any other line?

first set var to g, then truncate
for /F %%g in (pdblist.txt) do (
set var=%%g
set var2=!var:~0,4!
set trim=!var2!no_H.pdb
echo !trim!
set build=!var2!h.pdb
echo !build!
my pdblist.txt contains first_item, second_item (1 per line). output is:
first_item
firsno_H.pdb
firsh.pdb
second_item
secono_H.pdb
secoh.pdb

Related

Problem with EnableDelayedExpansion, For, and filenames with special characters like ! % &

The Setup:
I have a set of files of type .type1 and want to batch convert them to .type2 using a program I have
The converting program Program.exe (in a folder called TOOLS) takes two arguments -i for InputFile and -o for OutputFile but is unable to create folders/directories (if the output folder doesn't exist it fails)
The .type1 files are in different folders. All of these folders are in a folder called InputFolder
I want the .type2 converted files to be outputted to the OutputFolder preserving the folder structure of the originals
So, In the main folder I have 4 things:-
A. InputFolder :where all the input files (divided into different folders) exist
B. OutputFolder:where all the converted files should be outputted (divided into different folders matching the InputFolder)
C. TOOLS :where the converter Program.exe exists
D. Batch Convert.bat :the batch file I wrote to batch convert the files. The contents of which are in the next section
What I tried:
rem -------Setting some general variables-------
set "BatchPath=%~dp0"
set "InputPath=%BatchPath%InputFolder\"
set "OutputPath=%BatchPath%OutputFolder\"
rem -------Saving a list of all .type1 files-------
dir /s/b/a-d "%InputPath%*.type1">"%BatchPath%TOOLS\FilesList.txt"
rem -------Starting a loop for each file listed in FilesList.txt -------
for /f "usebackq delims=" %%j in ("%BatchPath%TOOLS\FilesList.txt") do (
setlocal EnableDelayedExpansion
rem --Setting variables replacing "input string" with "output string"--
set "InputFileType2=%%~dpnj.type2"
set "OutputFile=!InputFileType2:%InputPath%=%OutputPath%!"
set "InputFilePath=%%~dpj"
set "OutputFilePath=!InputFilePath:%InputPath%=%OutputPath%!"
rem --Creating output folders--
mkdir "!OutputFilePath!"
rem --Start the converting process--
"%BatchPath%TOOLS\Program.exe" -i "%%j" -o "!OutputFile!"
endlocal
)
The Problem:
Some of the folders and the files inside the InputFolder have special characters (like ! % &) which cause problems with the converting.
Is there a way to do this with the least amount of conflict with special characters (like removing the need to EnableDelayedExpansion to remove conflict with !?
is there a way to do it without the PwerShell or the Call function?
(because I have thousands of big files and the Call function can be slow and it seems like it always tries to access the HDD first before a :Label)
As compo said, you just need to change the order of lines.
It's important to expand the FOR variables only with delayed expansion disabled.
Because expanding them inside delayed expansion enabled, destroys the exclamation marks !
for /f "usebackq delims=" %%j in ("%BatchPath%TOOLS\FilesList.txt") do (
rem --Setting variables replacing "input string" with "output string"--
set "InputFileType2=%%~dpnj.type2"
set "OutputFile=!InputFileType2:%InputPath%=%OutputPath%!"
set "InputFilePath=%%~dpj"
set "helper=%%j"
setlocal EnableDelayedExpansion
set "OutputFilePath=!InputFilePath:%InputPath%=%OutputPath%!"
rem --Creating output folders--
mkdir "!OutputFilePath!"
rem --Start the converting process--
"%BatchPath%TOOLS\Program.exe" -i "!helper!" -o "!OutputFile!"
endlocal
)

How to copy a file on a network drive to another folder on network and add time stamp to copied file?

This script looks at a network location for a folder name and specific file and then should copy the file to other folder on the network with current timestamp in destination file name.
Can you advise any syntax error or reason why it is not copying?
ECHO on
Title %0
set GETfn=Q:\Cdata\mm_tn
set GETfn=%GETfn: =%
echo GETfn = %GETfn%
set f1=%GETfn%%m%%d%%y%-%hr%%mn%.csv
set f1=%f1: =%
echo f1 = %f1%
copy GETfn.csv Q:\FTP\Sent\%f1%
dir Q:\FTP\Sent\
For example, if i have specificfile.csv on a mapped network drive Q:\Cdata\mm_tn\
then using this:
#echo off
:: src -> destination
set src=Q:\Cdata\mm_tn\
set dst=Q:\FTP\Sent\
echo -------------------------------------
echo source dir ---^> %src%
echo destination dir ---^> %dst%
echo -------------------------------------
:: timestamp
:: https://stackoverflow.com/questions/1064557/creating-a-file-name-as-a-timestamp-in-a-batch-job
FOR /F %%A IN ('WMIC OS GET LocalDateTime ^| FINDSTR \.') DO (
#SET B=%%A
)
set timestamp=%B:~4,2%_%B:~6,2%_%B:~0,4%_%B:~8,2%-%B:~10,2%
echo %timestamp%
:: copy from Q:\Cdata\mm_tn\ -> Q:\FTP\Sent\
copy %src%specificfile.csv %dst%%timestamp%_specificfile.csv
the specificfile.csv is copied to Q:\FTP\Sent\ as timestamped file 12_17_2020_12-39_specificfile.csv. Now paths can be easily adjusted for your requirements.
The second block is:
set GETfn=Q:\Cdata\mm_tn
set GETfn=%GETfn: =%
echo GETfn = %GETfn%
This block first defines the environment variable GETfn with string value Q:\Cdata\mm_tn. Next it uses a string substitution to remove all spaces from the string assigned to environment variable GETfn. That is of course a completely useless command line as the folder path assigned to the environment variable does not contain any space at all on having the batch file written without trailing space(s) on the line above. The last line of this block just outputs the fixed folder path which makes also no real sense.
The third block is:
set f1=%GETfn%%m%%d%%y%-%hr%%mn%.csv
set f1=%f1: =%
echo f1 = %f1%
It defines an environment variable f1 being a concatenation of the strings assigned to the environment variables GETfn (defined above), m, d, y, hr and mn not defined in posted code at all. So f1 is defined with Q:\Cdata\mm_tn-.csv which is of course not right. The next line is again useless as it removes all spaces from the string assigned to environment variable f1 not containing any space at all, except the batch file contains one or more trailing spaces at end of the line above. The third line just outputs the wrong defined environment variable f1.
I recommend to open a command prompt, run set /? and read the output help carefully and completely from top of first to bottom of last page. Next I suggest to read my answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line? It has some useful additional information about the usage of command SET.
Please read carefully and completely my answer on Time is set incorrectly after midnight. Then you should have the knowledge why the following command line is a replacement for the entire posted batch file code.
#if exist "Q:\Cdata\mm_tn\GETfn.csv" for /F "tokens=1-5 delims=/: " %%I in ('%SystemRoot%\System32\robocopy.exe "%SystemDrive%\|" . /NJH') do #copy "Q:\Cdata\mm_tn\GETfn.csv" "Q:\FTP\Sent\GETfn_%%J%%K%%I-%%L%%M.csv" & goto :EOF
That command line copies the file Q:\Cdata\mm_tn\GETfn.csv to directory Q:\FTP\Sent with new file name GETfn_MMddyyyy-hhmm.csv using current date/time.
I would not use this date format for the destination file name. It would be better to use GETfn_yyyyMMdd-hhmm.csv, or better to read GETfn_yyyy-MM-dd_hh-mm.csv. This is the international date format which has the big advantage that files sorted by name are with such a date/time format sorted at the same time in chronological order. That is very often very helpful. So better in my opinion would be:
#if exist "Q:\Cdata\mm_tn\GETfn.csv" for /F "tokens=1-5 delims=/: " %%I in ('%SystemRoot%\System32\robocopy.exe "%SystemDrive%\|" . /NJH') do #copy "Q:\Cdata\mm_tn\GETfn.csv" "Q:\FTP\Sent\GETfn_%%I-%%J-%%K_%%L_%%M.csv" & goto :EOF
For understanding the used commands in the single command line and how they work, open a window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
copy /?
for /?
goto /?
if /?
robocopy /?
See also:
Where does GOTO :EOF return to?
Single line with multiple commands using Windows batch file

Trying to make a menu in a windows command prompt

I have a batch file that gets run by the user typing:
usercompile filename
usercompile is a batch file that does this:
copy /y %1.txt lib\incoming_file.txt
and then starts the compiler:
compiler.exe
The compiler has the "incoming_file" name hard-coded into linked source (this can't be chaged), so the current method is simply to copy the user file in and rename it to the known name and run the compiler.
I'd like to present the user with a list of files that are generated when a batch file is run, then the batch file would copy the selected file in, rename it (just like is done now).
So it would look like this:
Please choose a file to compile:
1) matthews_build
2) marks_build
3) lukes_build
and then the user would type 1 or 2 or 3 (in this case) and press enter. The batch file would copy that file to the known file name and launch the compiler. The one good thing is that the files that need to be listed all have a unique extension (.jal).
Any ideas?
I changed my approach and consider my previous answer a bad practice: re-listing the files with a second dir command unnecessarily reads the disk again, not to mention the rare but possible case if a file is added/removed between the 2 dir's and makes the whole thing unreliable.
Based on this brilliant solution I did a possible implementation with dynamic array:
#echo off
set /a counter=0
setlocal enabledelayedexpansion
FOR /f "delims=|" %%i IN ('dir /b /on "yourpath*.jal"') DO (
set /a counter+=1
rem echo !counter!^) %%~ni
set FileList[!counter!]=%%~ni & rem This is an array element, a dinamically created variable
)
rem Iterate through variables:
FOR /l %%i IN (1,1,!counter!) DO (
echo %%i^) !FileList[%%i]!
)
set /p option="Choose an option: "
echo !FileList[%option%]!
endlocal
This makes the file list available for any number of following commands.
One possible solution is to list all .jal files and give them an option number, store the result, and based on user input, look up the file based on the option number. As I know no way of storing such a result in memory (no array/hash table data type), only in a file, if a file can not be used, then the listing should be repeated in a deterministic way so that if we re-assign the option numbers, we get the same result. We can do it ensuring alphabetical ordering.
Here is one implementation:
BLOCK 1
setlocal enabledelayedexpansion
FOR /f "delims=|" %%i IN ('dir /b /on "yourpath\*.jal"') DO (
set /a counter+=1
echo !counter!^) %%~ni
)
endlocal
The nested dir command ensures alphabetical ordering (reference.)
A remark why I put a pipe (|) as a delimiter: if you don't define a delimiter, the default space will be used. If your file name contains space then it would be truncated. So I picked a character that is not valid in file names ensuring the whole file name is returned.
Now if you get a number from the user by this:
set /p option=Choose your option:
after this command (evaluating and possibly re-requesting the input) to do a lookup for the file you can repeat BLOCK 1 but replace the echo line with examining the option like this:
if !counter! == %option%
and put those commands in the if block to do whatever you want to do with the file (for debugging, put back the echo command).

Batch file locating duplicate patterns in filename then process

Ok, i've been working on a batch file for some time now, and im just stuck on the last bit.
What im trying to accomplish is to loop through a directory, create a variable which stores the filename of each file in the directory without the extension. Then for each file in the first loop, loop through a different directory and try to find any filename in the second loop that has the same name as stored in the variable, and then just output some simple text.
So for instance lets say in the first directory there is a filename called imafile-yehyeh.png, the variable will save imafile-yehyeh, then it will loop through all the files in the second directory, and output a message for each filename that has that pattern in it, so if a file in the second directory is called imafile-yehyeh_01.mp4 or imafile-yehyeh-newtitle.jpg, they would match the pattern and a message would output.
My script is looping and i am able to echo out all the variables, the files exist as i have created them exactly as shown above, but its not echoing out the filename is set for deletion line.
Any help would be greatly appreciated. my code is as follows;
#echo off
set "parent_folder=C:\Users\Testing\script"
set "dupe_folder=DUPEFOLDER"
set "kill_folder=1 SCANNED\thumb"
setlocal enableDelayedExpansion
for %%X in ("%parent_folder%\%dupe_folder%\*") do (
set dupe_pattern=%%~nX
for %%F in ("%parent_folder%\%kill_folder%\*") do (
echo %%~nF | FIND "%dupe_pattern%" 1>NUL && (
echo %%~F is set for deletion.
)
)
)
endlocal
Thanks to #Squashman the answer was to remove the set dupe_pattern.... line
and then change the FIND command to the following;
FIND "%%~nX"
Apart from needlessly setting a variable, as already pointed out, you are also making the script inefficient. For every file in the dupe_folder you are Echoing every file name in the kill_folder and piping that into a Find command looking for matches.
Here's a simpler way of doing it, (it matches file names which begin with the same string followed by a dot, as opposed to any file name containing the string anywhere).
#Echo Off
Set "parent_folder=C:\Users\Testing\script"
Set "dupe_folder=DUPEFOLDER"
Set "kill_folder=1 SCANNED\thumb"
CD /D "%parent_folder%" 2>Nul || Exit /B
For %%A In ("%kill_folder%\*") Do If Exist "%dupe_folder%\%%~nA.*" (
Echo %%A is set for deletion.)

String substition but whole line isn't copied

Hi I have this code to substitute the path and then run iexpress to build an exe.
#echo off
set PATH=PATH
set FOLDER=FOLDER
set NEWPATH=%~dp0
set TARGET=%NEWPATH%install_32bitWindows.EXE
echo %TARGET%
setlocal enabledelayedexpansion
for /f "tokens=2*" %%i in (install_32bitWindows.SED) do (
set str=%%i
echo %str%
set str=!str:%PATH%=%TARGET%!
set str=!str:%FOLDER%=%NEWPATH%!
echo !str! >> newfile
)
del install_32bitWindows.SED
rename newfile install_32bitWindows.SED
C:/Windows/SysWOW64/iexpress.exe /N %~dp0install_32bitWindows.SED
The substitution is done correctly but my problem is that one of the lines a space in it, and everything after the space isn't copied as such:
Originally
AppLaunched=c:\windows\system32\cscript.exe "install_32bitWindows.vbs"
After script:
AppLaunched=c:\windows\system32\cscript.exe
Why does the rest of the line get removed?
Thanks
Because all tokens after the second are concatenated into the implied %%j variable, which you are not referring to anywhere.
I 'm not sure what the correct processing would be, but this should point you to the correct direction:
>> newfile echo !str! %%j
I have moved the redirection to the beginning of the command so that the space before the >> is not spuriously inserted into the output file. Small stuff, but why not be precise?
In the absence of sample data, this becomes a bit of a guessing game.
Assuming your original ...SED filecontains lines of
string=anotherstring
and you wish to substitute different for certain fixed strings in that file, then
for /f "tokens=1*delims==" %%i in (install_32bitWindows.SED) do (
set str=%%j
(Note: 1* and %%j
should work BUT...
You appear to be substituting the newly-created file for the original, but the new file won't start string= because you don't output that part. If you want string=newstring then
echo %%i=!str! >> newfile
Finally, it's a really bad idea to use PATH as a user-variable in batch. PATH contains a semicolon-separated list of directories which batch uses to locate executables if the executable doesn't exist in the current directory. You change it, and batch will get amnesia vey quickly. Same goes for temp and tmp (point to a temporary directory) and a few other "reserved" names...

Resources