Making A List Of Images in a folder - windows

I need to send some images to a program at once, it will accept them with the format below:
"1.jpg" "2.jpg" "3.jpg" ...
The spaces between filenames with quotes is necessary, I mean this will be wrong: "1.jpg""2.jpg", space is required.
Now I want to declare an variable named list which stores names of all images in a folder.
for example List="1.jpg" "2.jpg" "3.jpg"
How to do that?

This should do what you're after:
#echo off
setlocal enabledelayedexpansion
set arglist=
for %%i in (*.txt) DO set arglist=!arglist! "%%i"
echo file.exe %arglist:~1% ::This is just for testing
ENDLOCAL
pause
The %arglist:~1% is just ignoring the first character because it's an unwanted space from the concatenation process

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
)

Windows Batch file - strip leading characters

I have a batch file which copies some local files up to a google storage area using the gsutil tool. The gsutil tool produces a nice log file showing the details of the files that were uploaded and if it was OK or not.
Source,Destination,Start,End,Md5,UploadId,Source Size,Bytes Transferred,Result,Description
file://C:\TEMP\file_1.xlsx,gs://app1/backups/file_1.xlsx,2018-12-04T15:25:48.428000Z,2018-12-04T15:25:48.804000Z,CPHHZfdlt6AePAPz6JO2KQ==,,18753,18753,OK,
file://C:\TEMP\file_2.xlsx,gs://app1/backups/file_2.xlsx,2018-12-04T15:25:48.428000Z,2018-12-04T15:25:48.813000Z,aTKCOQSPVwDycM9+NGO28Q==,,18753,18753,OK,
What I would like to do is to
check the status result in column 8 (OK or FAIL)
If the status is OK then move the source file to another folder (so that it is not uploaded again).
The problem is that the source filename is appended with "file://" which I can't seem to remove, example
file://C:\TEMP\file_1.xlsx
needs to be changed into this
C:\TEMP\file_1.xlsx
I am using a for /f loop and I am not sure if the manipulation of the variables %%A is different within a for /f loop.
#echo off
rem copy the gsutil log file into a temp file and remove the header row using the 'more' command.
more +1 raw_results.log > .\upload_results.log
rem get the source file name (column 1) and the upload result (OK) from column 8
for /f "tokens=1,8 delims=," %%A in (.\upload_results.log) do (
echo The source file is %%A , the upload status was %%B
set line=%%A
set line=!line:file://:=! >> output2.txt echo !line!
echo !line!
)
The output is like this.
The source file is file://C:\TEMP\file_1.xlsx , the upload status was OK
The source file is file://C:\TEMP\file_2.xlsx , the upload status was OK
I'm expecting it to dump the altered values out into a new file but it is not producing anything at the moment.
Normally I would extract from a specific character to the end of the string with something like this but it doesn't work with my For/f loop.
%var:~7%
Any pointers or a different way of doing it greatly appreciated.
Since the part to remove seems fixed it is easier to use substrings.
Also using for /f "skip=1" evades he neccessity of the external command more +1 and another intermediate file.
#echo off & setlocal EnableDelayedExpansion
type NUL>output2.txt
for /f "skip=1 eol=| tokens=1,8 delims=," %%A in (.\upload_results.log) do (
echo The source file is %%A , the upload status was %%B
set "line=%%A"
set "line=!line:~7!"
echo(!line!>>output2.txt
echo(!line!
)
File names and paths can contain also one or more exclamation marks. The line set line=%%A is parsed by Windows command processor a second time before execution with enabled delayed expansion. See How does the Windows Command Interpreter (CMD.EXE) parse scripts? Every ! inside the string assigned to loop variable A is on this line interpreted as begin or end of a delayed expanded environment variable reference. So the string of loop variable A is assigned to environment variable line with an unwanted modification if file path/name contains one or more exclamation marks.
For that reason it is best to avoid usage of delayed expansion. The fastest solution is for this task using a second FOR to get file:// removed from string assigned to loop variable A.
#echo off
del output2.txt 2>nul
for /F "skip=1 tokens=1,8 delims=," %%A in (upload_results.log) do (
echo The source file is %%A , the upload status was %%B.
for /F "tokens=1* delims=/" %%C in ("%%~A") do echo %%D>>output2.txt
)
Even faster would be without the first echo command line inside the loop:
#echo off
(for /F "skip=1 delims=," %%A in (upload_results.log) do (
for /F "tokens=1* delims=/" %%B in ("%%~A") do echo %%C
))>output2.txt
The second solution can be written also as single command line:
#(for /F "skip=1 delims=," %%A in (upload_results.log) do #for /F "tokens=1* delims=/" %%B in ("%%~A") do #echo %%C)>output2.txt
All solutions do following:
The outer FOR processes ANSI (fixed one byte per character) or UTF-8 (one to four bytes per character) encoded text file upload_results.log line by line with skipping the first line and ignoring always empty lines and lines starting with a semicolon which do not occur here.
The line is split up on every occurrence of one or more commas into substrings (tokens) with assigning first comma delimited string to specified loop variable A. The first solution additionally assigns eighth comma delimited string to next loop variable B according to ASCII table.
The inner FOR processes the string assigned to loop variable A with using / as string delimiter to get assigned to specified loop variable file: and to next loop variable according to ASCII table the rest of the string after first sequence of forward slashes which is the full qualified file name.
The full qualified file name is output with command echo and appended either directly to file output2.txt (first solution) or first to a memory buffer which is finally at once written into file output2.txt overwriting a perhaps already existing file with that file name in current directory.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
del /?
echo /?
for /?
See also the Microsoft article about Using command redirection operators for an explanation of the redirections >, >> and 2>nul

String replacement within FOR /F into batch file

There are a handful of questions on SO that look similar, but I cannot figure out some behaviour and I am looking for help.
Below is a snippet from a batch file I am trying to write which will load in a set of directories and potentially replace letter substitutions with an expanded path, e.g. the properties file might look like:
location1=C:\Test
location2=[m]\Test
Where location1 points to C:\Test and location2 points to C:\Program Files(x86)\MODULE\Test, because [m] is a shorthand to C:\Program Files(x86)\MODULE.
The batch script, to this point, is simply trying to read in the list of file paths and expand/replace the [m].
SET build.dir=%~dp0%
SET progfiles=%PROGRAMFILES(X86)%
IF "%progfiles%"=="" SET progfiles=%ProgramFiles%
SET local.properties=%build.dir%local.properties
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "tokens=1* delims==" %%i IN (%local.properties%) DO (
SET local.dir=%%j
SET local.dir=!local.dir:[m]=%progfiles%\MODULE!
echo !local.dir!
)
ENDLOCAL
Running this kicks out an error:
\MODULE was unexpected at this time.
If I replace the FOR with the following instead:
set test="[m]\Proj\Dir"
set test=!test:[m]=%progfiles%\MODULE!
echo %test%
I get the desired C:\Program Files(x86)\MODULE\Proj\Dir printed out...so I'm confused why it works fine outside of the FOR loop.
My understanding about delayed expansion is that it 'expands' at runtime...which you get to happen using !! instead of %% wrapped around the variable. Furthermore, as I'm creating the local.dir variable inside the FOR loop scope, I must use delayed expansion in order to access it with the updated value for the iteration.
I feel like the problem is using %progfiles%, like there's some special syntax I need to use in order to make it work but nothing is adding up for me. When I echo %progfiles%, it prints out as C:\Program Files(x86 -- note the missing trailing ).
Any ideas? Thanks
Tested suggestion:
D:\Projects\Test\Build>test
*** "D:\Projects\Test\Build\local.properties"
*** "","C:\Program Files (x86)"
[m]=C:\Program Files (x86)\MODULE
Adding quotes around the whole expression makes it work -- can't use other characters for some reason (like []) -- and since I want to append to the path later, we can safely remove the quotes afterwards:
SET local.dir="!local.dir:[m]=%progfiles%\MODULE!"
SET local.dir=!local.dir:"=!
Test this to see if you can nut out the issue:
The double quotes are to provide robust handling in a system with long file/path names.
The () are unquoted which are a problem in a batch script, when inside a loop.
#echo off
SET "build.dir=%~dp0%"
SET "progfiles=%PROGRAMFILES(X86)%"
IF "%progfiles%"=="" "SET progfiles=%ProgramFiles%"
SET "local.properties=%build.dir%local.properties"
echo *** "%local.properties%"
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "usebackq tokens=1* delims==" %%i IN ("%local.properties%") DO (
SET "local.dir=%%j"
echo *** "!local.dir!","%progfiles%"
SET "local.dir=!local.dir:[m]=%progfiles%\MODULE!"
echo !local.dir!
)
ENDLOCAL
pause
It has to do with the () characters that end up in your progfiles string. If you take them out, the substitution seems to work fine.
My suggestion is to ditch command for this particular purpose and use one of the other standard tools that Windows comes with. While my personal preference would be Powershell (since it's so much more powerful and expressive), you may just need something quick that you can integrate into existing cmd.exe stuff.
In that case, try the following VBScript file, xlat.vbs:
set arg = wscript.arguments
wscript.echo Replace(arg(0),arg(1),arg(2))
Your batch file then becomes something like, noting the inner for /f which captures the output of the VBS script and assigns it to the variable:
#echo off
SET build.dir=%~dp0%
set progfiles=%PROGRAMFILES(X86)%
if "%progfiles%"=="" set progfiles=%ProgramFiles%
set local.properties=%build.dir%local.properties
setlocal enabledelayedexpansion
for /f "tokens=1* delims==" %%i in (%local.properties%) do (
set local.dir=%%j
for /f "delims=" %%x in ('cscript.exe //nologo xlat.vbs "!local.dir!" "[m]" "%progfiles%\MODULE"') do set local.dir=%%x
echo !local.dir!
)
endlocal
Running that, I get the output:
C:\Test
C:\Program Files (x86)\MODULE\Test
which I think is what you were after.

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...

For loop in batch file reading a file of File Paths

I want to write a Windows batch file script that will loop through a text file of FILE PATHS, do some work using data from each file path, then ultimately delete the file.
I started by running the FORFILES command and sending its output (the #PATH parameter is the full path of any file it matches) to a text file (results.txt).
I end up with a results.txt file like this:
"C:/Windows/Dir1/fileA.log"
"C:/Windows/Dir1/fileA.log"
"C:/Windows/Dir2/fileC.log"
"C:/Windows/Dir3/fileB.log"
What I want to do is:
Use a FOR loop and read each line in the results.txt file
For each line (file path), strip out the directory name that the log file is sitting in (ie: Dir1, Dir2, etc..) and create a directory with that SAME name in a different location (ie. D:/Archive/Backups/Dir1, D:/Archive/Backups/Dir2, etc..) -- assuming the directory doesn't exist.
Move the actual .log file to a zip file in that directory [I have code to do this].
Delete the .log file from its original location. [Pretty straightforward]
I'm having trouble figuring out the best way to accomplish the first 2 steps. My FOR loop seems to stop after reading the very first line:
FOR /F "tokens=1,2,3,4,5,6,7,8,9,10 delims=\" %%G in ("results.txt") DO (
...
)
You don't want to parse the path with the tokens/delims options because you don't know how many directory levels you are dealing with. You want to preserve each line in its entirety. TO parse the path you want to use the FOR variable modifiers. (type HELP FOR from the command line and look at the last section of the output)
%%~pG gives the path (without the drive or file name). If we then strip off the last \, we can go through another FOR iteration and get the name (and possible extension) of the file's directory by using %%~nxA.
The toggling of delayed expansion is just to protect against a possible ! in the path. If you know that no path contains ! then you can simply enable delayed expansion at the top of the script and be done with it.
EDIT - this code has been modified significantly since Aacini pointed out that I misread the requirements. It should satisfy the requirements now.
for /f "usebackq delims=" %%G in ("results.txt") do (
set "myPath=%~pG"
setlocal enableDelayedExpansion
for /f "eol=: delims=" %%A in ("!myPath:~0,-1!") do (
endlocal
if not exist d:\Archive\Backups\%%~nxA md d:\Archive\Backups\%%~nxA
rem ::zip %%G into zip file in the D: location
rem ::you should be able to create the zip with the move option
rem ::so you don't have to del the file
)
)
I wrote this to timestamp files before offloading to SFTP.
Hope you find it useful.
The timestamp coding may seem irrelevant to your issue, but I left it because it's a good example of dissecting the filename itself.
I suggest you put an ECHO in front of the REN command for testing. Different shells may have different results.
In the end, the delayedexpansion command wasn't necessary. It was the sub-routine that fixed my issues with variables inside the loop. That could possibly be because of my OS ver. (Win 8.1) - It wouldn't hurt to leave it.
#echo off
cls
setlocal enabledelayedexpansion
if %time:~0,2% geq 10 set TIMESTAMP=%date:~10,4%%date:~4,2%%date:~7,2%_%time:~0,2%%time:~3,2%%time:~6,2%
if %time:~0,2% leq 9 set TIMESTAMP=%date:~10,4%%date:~4,2%%date:~7,2%_0%time:~1,1%%time:~3,2%%time:~6,2%
echo TimeStamp=%TIMESTAMP%
echo.
for %%G in (*.txt) do (
set OLDNAME=%%G
call :MXYZPTLK
)
dir *.txt
goto :EOF
:MXYZPTLK
echo OldName=%OLDNAME%
ren %OLDNAME% %OLDNAME:~0,-4%_%TIMESTAMP%%OLDNAME:~-4,4%
echo.
:END
You have two minor problems:
The path separator in the file is '/' but you use '\' in the for loop.
The quotes around "results.txt" stop it working.
This works. Don't write quotes to results.txt and you won't get a quote at the end of the filename.
#echo off
FOR /F "tokens=3,4 delims=/" %%I in (results.txt) DO (
REM Directory
echo %%I
REM File
echo %%J
)

Resources