I need to search multiple files within a folder in batch script and echo the not exist file and assign a variable for further logging, but unable to achieve that whenever my pattern contain (*) mark. Anyway i can achieve this?
SET pattern="abc*.txt" "ijk_*.txt" "xyz_*.txt"
SET count=0
FOR %%A IN (%pattern%) DO (IF EXIST "%%A" (SET /a count+=1) ELSE (
ECHO %date% %time%: %%A file missing.
SET fileList=!fileList! %%A
))
You can use a trick and split pattern into a multi-line variable and than iterate over each line. I'm using the question mark ? as a delimeter because it is a reserved character and can't be used within file names.
#echo off
SETLOCAL EnableDelayedExpansion
set patternlist="abc*.txt"?"ijk _*.txt"?"xyz_*.txt"
set pattern=!patternlist:?=^
!
SET count=0
FOR /F "delims=" %%A IN (!pattern!) DO (
if exist %%A (
SET /a count+=1
) ELSE (
ECHO %date% %time%: %%A file missing.
SET fileList=!fileList! %%A
)
)
Related
I'm trying to write a code that does the following. I have some files in a directory with specific extensions. I have made a vector that contains all of them. Now I will want to rename each file to something else depending on their extension. So for that I'm trying to parce the created vector with a for loop in which I check for each element extension.
For now I won't rename it just echo it on the screen if the file with the .elf extension is found. I wrote this code but I get no echo as in there would be no .elf file in my directory. Please help me correct this. Thanks.
#echo off
setlocal enabledelayedexpansion
cd C:\Users\uidr0938\Desktop\Copy
set path=C:\Users\uidr0938\Desktop\Copy
set /a index=0
for /r %%i in (*) do (
set value[!index!]=%%i
set /a index+=1
)
set /a limit=%index%-2
for /l %%a in (0;1;%limit%) do (
if !value[%%a]! equ *.elf (
echo !value[%%a]!
)
)
endlocal
try with :
....
for /l %%a in (0;1;%limit%) do (
if "!value[%%a]:~-4!" equ ".elf" (
echo !value[%%a]!
)
)
when comparing string you cannot use wildcards.Here you can see some examples about batch substrings
Here is a slightly different way of doing it.
#IF NOT EXIST "%USERPROFILE%\Desktop\Copy\" #EXIT/B
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "_path=%USERPROFILE%\Desktop\Copy"
SET "_index=0"
FOR /F "DELIMS=" %%A IN ('WHERE/R "%_path%" * 2^>NUL') DO (SET/A "_index+=1"
SET "_value[!_index!]=%%A")
IF %_index% EQU 0 EXIT/B
FOR /F "TOKENS=1* DELIMS==" %%A IN ('SET _value['
) DO IF /I "%%~xB"==".elf" ECHO %%B
PAUSE
So in Windows Explorer, I have these files sorted like this:
I have this script to remove the brackets and one zero, and in case the trailing number is greater than or equal to 10, to remove two zeroes:
cd C:\folder
setlocal enabledelayedexpansion
SET /A COUNT=0
for %%a in (*.jpg) do (
SET /A COUNT+=1
ECHO !COUNT!
set f=%%a
IF !COUNT! GTR 9 (
set f=!f:^00 (=!
) ELSE (
set f=!f:^0 (=!
)
set f=!f:^)=!
ren "%%a" "!f!"
)
pause
However, once I run the code, I get this result:
So the batch file isn't going through the files "intuitively" like Windows Explorer shows them. Is there any way to change this? Or is there a better way to rename these files altogether?
This uses a different approach:
#echo off
cd C:\folder
setlocal enabledelayedexpansion
SET /A COUNT=0, REMOVE=2
for /F "delims=(" %%a in ('dir /B *.jpg') do (
SET /A COUNT+=1
ECHO !COUNT!
set "f=%%a"
IF !COUNT! EQU 10 SET "REMOVE=3"
for /F %%r in ("!REMOVE!") do set "f=!f:~0,-%%r!"
ren "%%a" "!f!!COUNT!.jpg"
)
pause
Here is a method that does not depend on the sort order used by the file system, preserving the numbers as occurring in the original file names.
For each file name (for instance, test_this_01 SELR_Opening_00000 (1).jpg), the portion after the last under-score _ is retrieved (00000 (1)). Then the parentheses and the space are removed and then the length is trimmed to five characters (00001). This string replaces the original one in the file name finally (test_this_01 SELR_Opening_00001.jpg); the file name must not contain the replaced portion (00000 (1)) multiple times (hence file names like this should not occur: test_this_00000 (1) SELR_Opening_00000 (1).jpg):
#echo off
setlocal DisableDelayedExpansion
rem // Define constants here:
set "LOCATION=."
set "PATTERN=*_* (*).jpg"
set /A "DIGITS=5"
pushd "%LOCATION%" || exit /B 1
for /F "usebackq eol=| delims=" %%F in (`
dir /B /A:-D /O:D /T:C "%PATTERN%"
`) do (
set "FILE=%%F"
setlocal EnableDelayedExpansion
set "LAST="
for %%I in ("!FILE:_=","!") do (
set "LAST=%%~nI" & set "FEXT=%%~xI"
set "FNEW=!FILE:%%~I=!"
)
set "LAST=!LAST:(=!" & set "LAST=!LAST:)=!"
set "LAST=!LAST: =!" & set "LAST=!LAST:~-5!"
ECHO ren "!FILE!" "!FNEW!!LAST!!FEXT!"
endlocal
)
popd
endlocal
exit /B
Adapt the directory location and the file search pattern in the top section of the script as you like.
After having tested, remove the upper-case ECHO command in order to actually rename files.
I have an issue with reading lines from a *.txt file in batch script to get a list of files.
If my file contain something like
File does not exist: release\devpath\readme.txt
File does not exist: release\mainline\readme!!!.txt
2 errors.
and my batch is
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
set count_to_sync=-1
for /f "tokens=*" %%i in (bubu.txt) do (
set line=%%i
echo %%i
if "!line:~0,9!" == "MD5 FAIL:" (
set /A count_to_sync+=1
set list[!count_to_sync!]=!line:~10!
)
if "!line:~0,20!" == "File does not exist:" (
set list[!count_to_sync!]=!line:~21!
set /A count_to_sync+=1
)
)
IF "%count_to_sync%" == "-1" (
ECHO Nothing to sync
) ELSE (
ECHO Files to sync
for /F "tokens=2 delims==" %%s in ('set list[') do (
echo %%s
)
)
The output is
File does not exist: release\devpath\readme.txt
File does not exist: release\mainline\readme.txt
2 errors.
Files to sync
release\devpath\readme.txt
release\mainline\readme.txt
and the '!!!' from second line is missing.
I know that if I remove SETLOCAL ENABLEDELAYEDEXPANSION from batch the output will be
File does not exist: release\devpath\readme.txt
File does not exist: release\mainline\readme!!!.txt
2 errors.
First part is OK, but the extraction will not work because delayed expansion is disabled.
How I can get the correct output?
Thank you
UPDATE
The input file with all types of lines
File does not exist: release\devpath\readme.txt
File does not exist: release\mainline\readme!!!.txt
MD5 FAIL: exf.exe
2 errors.
UPDATE
I need this script to sync changed files based on the output of 'exf.exe' used to check the integrity of folder based on md5 checksum
When the specifications of a problem are not described, but based on examples, we can make assumptions that may or may not be correct. My assumption is that you want the last token of the lines in your text file, so this is a possible (and much simpler) solution:
EDIT: I changed my original method for a simpler one.
#echo off
setlocal
set "msg=Nothing to sync"
(for /F "tokens=3,5" %%a in (bubu.txt) do (
set "msg=Files to sync"
if "%%b" neq "" (echo %%b) else echo %%a
)) > list.txt
echo %msg%
type list.txt
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q35477317.txt"
ECHO Files to sync
FOR /f "usebackqtokens=4*delims=: " %%a IN ("%filename1%") DO ECHO(%%b
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
I used a file named q35477317.txt containing your data for my testing.
It's not clear why you've taken your approach - is there something you haven't told us?
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q35477317.txt"
ECHO Files to sync
FOR /f "usebackqtokens=1*delims=:" %%a IN ("%filename1%") DO (
FOR /f "tokens=*" %%c IN ("%%b") DO ECHO(%%c
)
GOTO :EOF
Easily fixed once we get the full story...
Maybe you need something like that:
#ECHO OFF
rem SETLOCAL ENABLEDELAYEDEXPANSION
set count_to_sync=-1
for /f "tokens=*" %%i in (bubu.txt) do (
set line=%%i
echo %%i
SETLOCAL ENABLEDELAYEDEXPANSION
if "!line:~0,9!" == "MD5 FAIL:" (
set /A count_to_sync+=1
set list[!count_to_sync!]=!line:~10!
)
if "!line:~0,20!" == "File does not exist:" (
set list[!count_to_sync!]=!line:~21!
set /A count_to_sync+=1
)
ENDLOCAL
)
IF "%count_to_sync%" == "-1" (
ECHO Nothing to sync
) ELSE (
ECHO Files to sync
for /F "tokens=2 delims==" %%s in ('set list[') do (
echo %%s
)
)
I'm trying to read a file and output the lines of data into registry keys. The data collection works, but I don't understand the syntax required to increment the string values in the last loop.
#echo OFF
SETLOCAL DisableDelayedExpansion
FOR /F "usebackq skip=1 delims=" %%a in (`"findstr /n ^^ C:\GetSID.txt"`) do (
set "var=%%a"
SETLOCAL EnableDelayedExpansion
set "var=!var:*:=!" This removes the prefix
echo(!var:~76,63!>>C:\SIDoutput.txt
goto :EndLoop
)
:EndLoop
set /p SID= <C:\users\paintic\SIDoutput.txt
set KEY_NAME="HKEY_USERS\!SID!\Software\Microsoft\Windows NT\CurrentVersion\PrinterPorts"
set Counter=1
for /f %%x in (C:\users\paintic\Networkprinters.txt) do (
set "Line_!Counter!=%%x"
set /a Counter+=1
if !Counter!==3 (Echo %line_counter%)
)
set /a counter2=!counter!-3
set counter=1
The part below is what I can't get to work. I'm trying to write LINE_1, LINE_2 and LINE_3 values from the previous loop to increment via the loop below. So VALUENAME should equal LINE_1, TYPE should = LINE_2's value and DATA should = LINE_3 on the first run and keep going up by 1 until the loop finishes (end of the file read)
`for /L %%i in (1,1,%counter2%) do (
set ValueName=%Line_!counter!%
set /a counter+=1
set Type=%Line_!counter!%
set /a Counter+=1
set Data=%Line_!counter!%
set /a Counter+=1
echo !ValueName!
echo !Type!
echo !Data!
REG ADD %KEY_NAME% /v !ValueName! /t !Type! /d !Data! /f
)
ENDLOCAL
Pause`
On searching for errors in batch file it is always helpful to use in first line #echo on or remove #echo off or comment this line with rem to see what cmd.exe really executes.
Command line interpreter fails on lines with set VariableName=%Line_!counter!% as the interpreter does not know what to expand first. I think it is not possible to create dynamically the name of an environment variable and reference next the value of this environment variable. This approach most likely does not work ever.
However, what you want to achieve can be done much easier directly in second loop as the following example demonstrates:
#echo off
setlocal EnableDelayedExpansion
rem Create data for demo example.
set "KEY_NAME=HKEY_USERS\S-1-5-20\Software\Microsoft\Windows NT\CurrentVersion\PrinterPorts"
echo TestValue>"%TEMP%\Networkprinters.txt"
echo REG_SZ>>"%TEMP%\Networkprinters.txt"
echo Sample Data>>"%TEMP%\Networkprinters.txt"
echo AnotherValue>>"%TEMP%\Networkprinters.txt"
echo REG_DWORD>>"%TEMP%\Networkprinters.txt"
echo ^1>>"%TEMP%\Networkprinters.txt"
rem Now the loop follows which reads the data from the file line
rem by line and build the line for using command "reg.exe" to
rem add the data to registry of the user with the defined SID.
set Counter=1
for /f "usebackq delims=" %%x in ("%TEMP%\Networkprinters.txt") do (
if "!Counter!"=="1" (
set "ValueName=%%x"
) else if "!Counter!"=="2" (
set "ValueType=%%x"
) else (
set "ValueData=%%x"
rem Echo the command instead of really executing "reg.exe".
echo reg.exe ADD %KEY_NAME% /v "!ValueName!" /t !ValueType! /d "!ValueData!" /f
set Counter=0
)
set /a Counter+=1
)
rem Delete the text file created for demo example.
del "%TEMP%\Networkprinters.txt"
endlocal
This solution is much easier than what you have tried and can be maybe even more simplified.
I have successfully made a script that filters out duplicate lines in a file and saves the results to a variable semi-colon separated (sort of an "array"). I could not find any real good solution to it.
#echo off
setlocal enabledelayedexpansion
rem test.txt contains:
rem 2007-01-01
rem 2007-01-01
rem 2007-01-01
rem 2008-12-12
rem 2007-01-01
rem 2009-06-06
rem ... and so on
set file=test.txt
for /f "Tokens=* Delims=" %%i in ('type %file%') do (
set read=%%i
set read-array=!read-array!;!read!
)
rem removes first trailing ";"
set read-array=!read-array:*;=!
echo !read-array!
for /f "Tokens=* Delims=" %%i in ('type %file%') do (
set dupe=0
rem searches array for the current read line (%%i) and if it does exist, it deletes ALL occurences of it
echo !read-array! | find /i "%%i" >nul && set dupe=1
if ["!dupe!"] EQU ["1"] (
set read-array=!read-array:%%i;=!
set read-array=!read-array:;%%i=!
)
rem searches array for the current read line (%%i) and if it does not exist, it adds it once
echo !read-array! | find /i "%%i" >nul || set read-array=!read-array!;%%i
)
rem results: no duplicates
echo !read-array!
Contents of !read-array! is 2008-12-12;2007-01-01;2009-06-06
I now want to take out each item in the array and write them to a new file, with line breaks after each item. Example:
2008-12-12
2007-01-01
2009-06-06
So this is what I've come up with so far.
The problem I'm having is that the second for-loop doesn't accept the !loop! variable as a token definition when being nested. It does however accept %loop% if it's not nested.
The reason I'm doing it this way is that the !read-array! may have a unknown number of items, therefore I count them as well.
Any ideas?
rem count items in array
set c=0
for %%i in (!read-array!) do set /a c+=1
echo %c% items in array
for /l %%j in (1,1,%c%) do (
set loop=%%j
for /f "Tokens=!loop! Delims=;" %%i in ("!read-array!") do (
echo %%i
rem echo %%i>>%file%
)
)
exit /b
At end of your first section, when contents of !read-array! is 2008-12-12;2007-01-01;2009-06-06, you may directly separate the elements of your "list" with a simple for because the standard separators in Batch files may be, besides spaces, comma, semicolon or equal signs:
for %%i in (%read-array%) do echo %%i
However, may I suggest you a simpler method?
Why not define a "real" array with the subscript value of the lines? This way, several repeated lines will store its value in the same array element. At end, just display the values of the resulting elements:
#echo off
set file=test.txt
for /F "Delims=" %%i in (%file%) do (
set read-array[%%i]=%%i
)
rem del %file%
for /F "Tokens=2 Delims==" %%i in ('set read-array[') do (
echo %%i
rem echo %%i>>%file%
)
EDIT
Alternative solution
There is another method that assemble a list of values separated by semicolon as you proposed. In this case each value is first removed from previous list content and immediately inserted again, so at end of the cycle each value is present just once.
#echo off
setlocal EnableDelayedExpansion
set file=test.txt
for /F "Delims=" %%i in (%file%) do (
set read-array=!read-array:;%%i=!;%%i
)
rem del %file%
for %%i in (%read-array%) do (
echo %%i
rem echo %%i>> %file%
)