Using windows batch file, I am trying to echo a list of file extensions in a folder.
That will then be set as %var% and output to .txt file
#setlocal & #(for %%I in (*.*) do #set /a ext[%%~xI] += 1) & set ext[
from this post Windows command to get list of file extensions
My end game is I would like it to output like so
folder contents:
sample1.jpg
sample2.jpg
sample3.jpg
sample4.mp4
sample5.mp4
sample6.png
sample7.zip
sample8.zip
result:
.jpg, .mp4, .png, .zip
Any help is greatly appreciated, I hope I explained it clear enough
You already have defined a variable for each extension. Just use another for /f loop to concatenate the relevant part (the actual extension) of them:
#echo off
setlocal enabledelayedexpansion
for %%I in (*) do #set /a ext[%%~xI] += 1
for /f "tokens=2 delims=[]" %%a in ('set ext[') do set "var=%%a, !var!"
echo %var:~0,-2%
#setlocal ENABLEDELAYEDEXPANSION&#(for %%I in (*.*) do #set /a ext[%%~xI] += 1&IF DEFINED ext[all] (IF "!ext[all]!" equ "!ext[all]: %%~xI=!" SET "ext[all]=!ext[all]!, %%~xI") ELSE (SET "ext[all]= %%~xI"))&SET "ext[all]=!ext[all]:~1!"&set ext[
Why you want this all on one line, I've no idea.
Since you need to access the changed value of a variable within a loop, you need delayedexpansion. Note that Space.ext is appended each time a new extension is found, so there will be an extra space at the start of the list variable - hence the requirement to remove the first character before displaying the result.
Related
This question already has answers here:
Arrays, linked lists and other data structures in cmd.exe (batch) script
(11 answers)
Closed 2 years ago.
I'm new to bat scripting and I wanted to use an iterative loop in my script (something like this in javascript for example)
for(var i=0;i<n;i++){
//my code here
console.log("my tab ["+i+"] is:"+tab[i];
}
So, basicaly this is my bat script in a file called exctract_excel_info.bat:
#ECHO OFF
::setlocal enabledelayedexpansion
:start
ECHO "Hi it's MIBE in this script i will list all the files with the extention xlsx or xls">log.txt
:start_loop
echo Listing all files in the current directory %cd% >log.txt
ECHO ================== ======================>>log.txt
set "AllowExt= *.xls"
ECHO the variable AllowExt in the first instruction %AllowExt%>>log.txt
set theFileName="NONE"
set /a i = 0
for %%a in (%AllowExt%) do (
set /a i = i + 1
::echo Found the file: "%%a">>log.txt
set theFileName[%i%]=%%a
)
:end_loop
ECHO ============================================>>log.txt
ECHO "The value of i is %i%">>log.txt
ECHO ============================================>>log.txt
for /L %%x in (1,1,%i%) do (
ECHO found the file %theFileName[%%x]%>>log.txt
)
ECHO ============================================>>log.txt
timeout /t 2
ECHO Yo the file %theFileName[0]% will be passed as a parameter
ECHO The array of files %theFileName%>>log.txt
:run_node
node main.js "%theFileName[0]%">>log.txt
timeout /t 2
:end
::PAUSE
I have a problem reading the value of the variable theFileName[i] in line 32
ECHO found the file %theFileName[%%x]%>>log.txt
This is the output (log.txt):
Listing all files in the current directory C:\Users\mibe\my bat
================== ======================
the variable AllowExt in the first instruction *.xls
============================================
"The value of i is 4"
============================================
So my problem is what is the proper way to read the value of the items inside theFileName array?
PS: when I comment the lines 31, 32, and 33:
for /L %%it in (1,1,"%i%") do (
ECHO found the file %theFileName[%%it]%>>log.txt
)
the script executes properly and get the value of %theFileName[0]%
The following is a basic example of what I think you're trying to do, up to a point.
The problem is that because you've not told us what exactly you're intending to do with those similarly named variables, I cannot include the specific methodology for doing so. I have therefore just output the defined variable names along side their value strings.
#SetLocal EnableExtensions DisableDelayedExpansion
#For /F "Delims==" %%G In ('"(Set File[) 2> NUL"') Do #Set "%%G="
#Set "i=0" & For /F Delims^= %%G In (
'"(Set PATHEXT=) & "%__APPDIR__%where.exe" ".:*.xlsx" ".:*.xls" ".:*.csv" 2> NUL | "%__AppDir__%sort.exe""'
) Do #(Set /A i += 1 & SetLocal EnableDelayedExpansion
For %%H In (!i!) Do #EndLocal & Set "File[%%H]=%%~nxG")
#If Defined File[1] For /L %%G In (1,1,%i%) Do #(SetLocal EnableDelayedExpansion
Echo File[%%G]=!File[%%G]! & EndLocal)
#Pause
The code above should define individual variables, each containing the string value of a file in the current directory, which has an extension of either .xlsx, .xls, or .csv.
When I first looked at your question I initially thought that you were intending to pass each file name together as multiple arguments to your node command.
If that is what you're actually intending to do, then I'd assume the following example would suit your purposes better.
#SetLocal EnableExtensions DisableDelayedExpansion
#Set "FileList="&For /F Delims^= %%G In (
'"(Set PATHEXT=) & "%__APPDIR__%where.exe" ".:*.xlsx" ".:*.xls" ".:*.csv" 2> NUL | "%__AppDir__%sort.exe""'
) Do #If Not Defined FileList (Set "FileList="%%~nxG"") Else (SetLocal EnableDelayedExpansion
For /F Delims^=^ EOL^= %%H In ("!FileList!") Do #EndLocal & Set "FileList=%%H "%%~nxG"")
#If Defined FileList Echo %%FileList%%=%FileList%
#Pause
The code above should define a single variable, containing the space separated, and doublequoted, string values, of each file in the current directory, which has an extension of either .xlsx, .xls, or .csv.
Please note that there is a command line length limitation so be aware that your value could become truncated.
In both examples:
The last line, #Pause, is included only to prevent premature closure of the cmd window, should you not be testing this from the CLI. (You can safely remove it if you are).
I assumed you wanted only the filenames without their paths, in the variable values. Should you wish for the full paths, just change %%~nxG in your chosen example code to %%G.
BTW, I used sort.exe against the returned files, because you mentioned array, and IMO an array should be ordered. (If you do not need that functionality, you could remove | "%__AppDir__%sort.exe" from your chosen example code).
Please note that there is a limit to the size of the environment, so be aware that if you have many matching files, they have long filenames, include paths etc. you may reach or exceed that limitation.
Having provided some examples for you, I'm not sure why you could not just iterate your directory, and create an array of those files, directly using .js, (off topic).
Ok so I'm super close to doing what I need to do.
I'm having an issue with my rename command and a double letter at the end of the folder. The folder names in the code have been changed for privacy, Spaces have been kept to show how the folders would be named.
The double letter is uppercase I (eye), this can't be changed.
Yes this file exists.
Example:
FolderII - error: The system cannot find the path specified.
Folder - Works
FolderI - works
for /r "C:\Folder Name" %%a in (*) do if "%%~nxa"=="FileFound" set p=%%~dpnxa
for /f "usebackq tokens=1* delims=." %%A in ("%p%") do set Build=%%B
for /f "tokens=2 delims==" %%G in ('wmic os get localdatetime /value') do set datetime=%%G
for /f "tokens=3 delims=\" %%Z in ("%p%") do set filepath=%%Z
set year=%datetime:~0,4%
set month=%datetime:~4,2%
set day=%datetime:~6,2%
set dbname=Logdb%year%.%Build%
REN "C:\Folder Name\%filepath%\%dbname%" "Logdb%month%-%day%-%year%.%Build%"
OUTPUT
EDITED!
CMD>REN "C:\Folder Name\FolderII\Logdb2020.ext" "Logdb11-23-2020.ext"
The system cannot find the file specified.
Added
CMD>REN "C:\Folder Name\Folder\Logdb2020.ext" "Logdb11-23-2020.ext"
THIS works
EDIT FOR CLARIFICATION*
I'll explain this how I intended it to work, which it does as long as the folder it's being assigned to doesn't have a II in it.
1st line: Search this particular folder for a file called "SYSCON" no extension, once found assign to p the file path of the file for 2nd line
2nd line:Open file found at 1st line and get the extension of the file listed inside the file and assign it to Build
3rd line:Get the current date to assign to the new file name in REN
4th line:Use the file path found in line 1 to get the folder name for the REN
5-7 set date variables
Line 8:Assign the new file name to variable
Line 9:Rename the old file at the location found to the new file name generated
I'm not a batch developer, I've literally written these lines as they work for me, but I'm always willing to learn how to do better, I'm a PHP programmer. This is a different project.
The folder structure is fluid for the application. The reason for the search for the initial file is to find the file in 1 of 4 folders and then get that actual folder name.
I can echo all the variables and see the correct file path, the correct file name and the correct new file name.
When it comes to rename the file in the folder with II, it fails to find the actual file to do the rename on, that's where I'm stuck.
IMAGE of Output echoed as it steps through the lines, for privacy sake I have to change the file names. Here's the CMD output for, I hope, better understanding
I'm not positive, based upon your lack of specific information, but as a best guess, I'd assume that something like this should perform the task, I think your example is trying to achieve.
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /F "Tokens=1-3 Delims=/ " %%G In (
'""%__AppDir__%Robocopy.exe" \: . /NJH /L | "%__AppDir__%find.exe" " 123""'
) Do Set "YYYY=%%G" & Set "MM=%%H" & Set "DD=%%I"
For /D %%G In (C:\Folder Name\*) Do For %%H In ("%%G\SYSCON"
) Do If "%%~aH" Lss "d" If "%%~aH" GEq "-" (
For /F "UseBackQ Tokens=1,* Delims=." %%I In ("%%H") Do Set "Build=%%J"
SetLocal EnableDelayedExpansion
Ren "%%G\Logdb%YYYY%.!Build!" "Logdb%MM%-%DD%-%YYYY%.!Build!"
EndLocal)
The example above expects the the string you're using for the Build variable is on the last non empty line of the target file, (ASCII text with CRLF line endings). If it is the only non empty line in that target file, then perhaps the following would be more useful:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /F "Tokens=1-3 Delims=/ " %%G In (
'""%__AppDir__%Robocopy.exe" \: . /NJH /L | "%__AppDir__%find.exe" " 123""'
) Do Set "YYYY=%%G" & Set "MM=%%H" & Set "DD=%%I"
For /D %%G In (C:\Folder Name\*) Do For %%H In ("%%G\SYSCON"
) Do If "%%~aH" Lss "d" If "%%~aH" GEq "-" (
For /F "UseBackQ Tokens=1,* Delims=." %%I In ("%%H"
) Do Ren "%%G\Logdb%YYYY%.%%J" "Logdb%MM%-%DD%-%YYYY%.%%J")
It would seem that the data assigned to build contains trailing spaces and perhaps some invisible characters. The easy way would be to simply change 1* to 1,2.
Since Space is a default delimiter, %%B will be assigned the value between the first and second spaces on the line. Tough if you want spaces in the extension, but do you really want to use extensions with spaces?
The syntax SET "var=value" (where value may be empty; in which case var becomes undefined) is used to ensure that any stray trailing spaces are NOT included in the value assigned.
I have two .txt files. One contains numbers, and the other one contains filepaths. I want to combine these two files to a .csv. The combination is based on wether the number (from nrs.txt) is in the string of the filepath (nodups.txt).
Now I have the following code for this:
#setlocal enableextensions enabledelayedexpansion
for /F %a IN (Output\nrs.txt) DO (
SET "nrs=%a"
for /F %b IN (Output\nodups.txt) DO (
SET "pathstring=%b"
SET csvdelim=,
IF NOT x!pathstring:%nrs%=""!==x%pathstring% %nrs%,%pathstring%>>new2017.txt
)
)
#endlocal
However, I keep having the following issues with the code:
The pathstring never seems to get set. (when I run the code without the if statement, The nrs variable gets set but the pathstring is set to %b). I've seen a lot of possible solutions on here already but none seem to work for me (setting variables like !var! and using usebackq).
The IF statement in the second for loop gets the following error message =""!==x%pathstring% was unexpected at this time. The ="" should remove the nr. from the path (if its there). When I replace "" with something else it still does not work.
The file contents are:
File nrs.txt:
12345
12245
16532
nodubs.txt:
C:\tmp\PDF_16532_20170405.pdf
C:\tmp\PDF_1234AB_20170405.pdf
C:\tmp\PDF_12345_20170506.pdf
Desired output:
12345, C:\tmp\PDF_12345_20170506.pdf
16532, C:\tmp\PDF_16532_20170405.pdf
I really hope someone can help me out with this !
This solution use a different approach, based on arrays:
#echo off
setlocal EnableDelayedExpansion
rem Load array from nodubs.txt file
pushd "Output"
for /F "tokens=1,2* delims=_" %%a in (nodubs.txt) do set "nodubs[%%b]=%%a_%%b_%%c"
rem Process nrs.txt file and show output
(for /F %%a in (nrs.txt) do (
if defined nodubs[%%a] echo %%a, !nodubs[%%a]!
)) > new2017.txt
In a batch file for variables need two percent signs.
There is no need to put %%A into a variable, use it directly.
#setlocal enableextensions enabledelayedexpansion
for /F %%a IN (Output\nrs.txt) DO (
findstr /i "_%%a_" Output\nodups.txt >NUL 2>&1 || >>new2017.txt Echo %%a
)
#endlocal
Instead of a second for, I'd use findstr to search for the entry of nrs.txt enclosed in underscores.
if no find use condiotonal execution on failure || to write to the new file.
According to changed preliminaries another answer.
#Echo on
Pushd Output
for /F "tokens=1-3 delims=_" %%A IN (
' findstr /G:nrs.txt nodubs.txt'
) DO >>"..\new2017.txt" Echo %%B, %%A_%%B_%%C
Popd
sample output:
> type ..\new2017.txt
16532, C:\tmp\PDF_16532_20170405.pdf
12345, C:\tmp\PDF_12345_20170506.pdf
I want to define a big array (>400 keys) in batch, but when I execute my script the windows close. I use this setting:
set FILE_LIST=(filename1.xxx [...] filename450.yyy)
Some help? Thx
A Windows Batch file have a limit in the value of each variable to 8192 characters, including the name of the variable and the equal sign. If the value of each "filename#.xxx " have 16 characters, you may store up to 8192/16=512 file names in one variable; to do that, you must use Batch commands. For example:
#echo off
setlocal EnableDelayedExpansion
set "FILE_LIST="
for /L %%i in (1,1,450) do set "FILE_LIST=!FILE_LIST!filename%%i.xxx "
echo FILE_LIST=%FILE_LIST%
Please, note that previous variable is a list, NOT and array. To define an array, use this method:
#echo off
setlocal EnableDelayedExpansion
for /L %%i in (1,1,450) do set "FILE_ARRAY[%%i]=filename%%i.xxx"
echo FILE_ARRAY:
set FILE_ARRAY
There is a limit of 64 MegaBytes for the total space occupied by all variables.
For a detailed description of arrays and other data structures in Batch files, see: Arrays, linked lists and other data structures in cmd.exe Batch script
EDIT: Reply to the comments
The Batch file below assume that there is one file name per line in the .txt file, and that file names does not include exclamation marks:
#echo off
setlocal EnableDelayedExpansion
rem Load the .txt file in FILE_ARRAY elements:
set num=0
for /F "delims=" %%a in (fileList.txt) do (
set /A num+=1
set "FILE_ARRAY[!num!]=%%a"
)
rem Process the FILE_ARRAY elements:
for /L %%i in (1,1,%num%) do echo Processing: %%i- "!FILE_ARRAY[%%i]!"
I finaly use this way:
set FILE_ARRAY[0]=filename1.xxx
set FILE_ARRAY[1]=filename2.yyy
set FILE_ARRAY[2]=filename3.zzz
for /F "tokens=2 delims==" %%i in ('set FILE_ARRAY[') do (
echo %%i
)
Thanks for your answers.
Seems like you might be hitting a batch file limitation (link), The following link describes a WA for this issue as dumping what you want in a var into a file, then reading that file back in when you need that massive var.
Ah batch, and your endless workarounds...
Happy Friday Think-Tank!
I need some assistance with a Batch .BAT script. Specifically I need help with some "IF statement syntax"
I have a script that is renaming files. There are two files, one ending in four digits and the other ending in five digits. The files will be renamed with variables I have already pre-set earlier within my script.
So here is a scenario: We have two files in a directory located at
c:\Users\username\Desktop\test-dir
There are two files within test-dir:
file1.12345
file2.1234
A four digit ending is one variable type (VAR1), whereas a file ending in five digits is another variable type (VAR2).
I need an if statement to:
a) read all the files(s) with the chosen directory (without using a wildcard if possible).
b) determine based on the number of digits after the "." which variable to use.
c) once making that determination rename the file with the appropriate variables.
The final re-naming convention is as so: yyyymmddtype.1234/12345
So basically it would use the datestamp variable I already created, the type variable I already created to be injected by the if statement, and append with the original ending digits of the file.
I know this seems like a lot, but I am more so a bash script guy. I have all the elements in place, I just need the if statement and what feels like a for loop of some kind to tie it all together.
Any help would be great!
Thank you!
Sorry, not the option you where asking for. Instead of iterating over the full list checking each file for extension conformance, iterate over a list of patterns that will filter file list, renaming matching files with the asociated "type"
for %%v will iterate over variable list, for %%a will split the content of the variable in pattern and type, for %%f will generate the file list, filter with findstr using the retrieved pattern and rename matching files with the corresponding "type"
Rename command is preceded with a echo to output commands to console. If the output is correct, remove the echo to rename the files.
#echo off
rem Variables defined elsewhere
set "folder=c:\somewhere"
set "timestamp=yyyymmdd"
rem Rename pattern variables in the form pattern;type
set "var1=\.....$;type1"
set "var2=\......$;type2"
set "var1=\.[^.][^.][^.][^.]$;type1"
set "var2=\.[^.][^.][^.][^.][^.]$;type2"
setlocal enableextensions disabledelayedexpansion
for %%v in ("%var1%" "%var2%") do for /f "tokens=1,* delims=;" %%a in ("%%~v") do (
for /f "tokens=*" %%f in ('dir /a-d /b "%folder%" ^| findstr /r /c:"%%~a"') do (
echo ren "%folder%\%%~f" "%timestamp%%%~b%%~xf"
)
)
endlocal
#ECHO OFF &SETLOCAL
set "yyyymmdd=yyyymmdd"
set "VAR1=VAR1"
set "VAR2=VAR2"
for /f "delims=" %%a in ('dir /b /a-d^|findstr /re ".*\....."') do echo(ren "%%~a" "%yyyymmdd%%VAR1%%%~xa"
for /f "delims=" %%a in ('dir /b /a-d^|findstr /re ".*\......"') do echo(ren "%%~a" "%yyyymmdd%%VAR2%%%~xa"
remove echo( to get it working.
If I understand you then this will rename the two files using preset variables for each one:
for %%a in ("%userprofile%\Desktop\test-dir\*") do (
if "%%~xa"==".12345" ren "%%a" "%variableA%-%variableB%%%~xa"
) else (
ren "%%a" "%variableC%-%variableD%%%~xa"
)
)