Arrays on batch script - arrays

Everyone,
I'm trying to do a differential backup with svnadmin dump --incremental commmand. My idea is so basic, to read the multiple svn repositories using the command dir and to put into a text file called "input", to read it line by line and put into variables.
Get the last revision of the repositories with full backup script and write in a text file called "output" and put into a variables.
Everything is done, but I can't use the svnadmin dump because I need the variables (arrays) inside the loops. How can I do it? Please, help me, I tried so many times and doesn't work still ):
#echo off
cls
:: =================== CONFIG ============================================
:: Path of the dir containing your repos [Note Trailing slash]
SET repodir=E:\svn\repositorios
:: Path of the dir in which to create you dumps [Note Trailing slash]
SET repodump=E:\Backup\SVN
:: File to read (multiple directories)
SET "File2ReadInput=E:\Backup\SVN\input.txt"
SET "File2ReadOutput=E:\Backup\SVN\output.txt
SET "File2ReadOutputNew=E:\Backup\SVN\New\output_new.txt
:: =================== CONFIG ============================================
:: =================== SCRIPT ============================================
rem deleting old file output.txt
del E:\Backup\SVN\output.txt
rem deleting old file output_new.txt
del E:\Backup\SVN\New\output_new.txt
rem creating new file output.txt
for /f "delims=" %%f in ("E:\Backup\SVN\*.data") do type %%f >> E:\Backup\SVN\output.txt
rem creating input file
dir %repodir% /ad /b > E:\Backup\SVN\input.txt
rem reading input file
setlocal EnableExtensions EnableDelayedExpansion
for /f "delims=" %%a in ('Type "%File2ReadInput%"') do (
set /a count+=1
set "Line[!count!]=%%a"
)
For /L %%i in (1,1,%Count%) do (
echo "Var%%i" is assigned to ==^> "!Line[%%i]!"
echo E:\svn\repositorios\!Line[%%i]!
set REPO_NAME=!Line[%%i]!
:: getting new transactions to compare
for /F "delims=" %%g in ('svnlook youngest E:\svn\repositorios\!Line[%%i]!') do (
echo %%~g
) > E:\Backup\SVN\New\last_rev_!Line[%%i]!_new.data
)
:: creating a new file with new datas
for /f "delims=" %%h in ("E:\Backup\SVN\New\*.data") do type %%h >> E:\Backup\SVN\New\output_new.txt
rem reading output file (dento do segundo for porque eu preciso do !Line[%%i]!)
setlocal EnableExtensions EnableDelayedExpansion
for /f "delims=" %%b in ('Type "%File2ReadOutput%"') do (
set /a out_count+=1
set "Output[!out_count!]=%%b"
)
for /L %%n in (1,1,%out_count%) DO (
echo "Var%%n" is assigned to ==^> "!Output[%%n]:~0,-1!"
set PREVIOUS=!Output[%%n]!
)
for /F "delims=" %%u in ('svnadmin dump -r!Output[%%n]:~0,-1!:HEAD E:\svn\repositorios\!Line[%%i]! --incremental') do (
echo %%~u
)> > E:\Backup\SVN\svn_backup_diff_!Line[%%i]!.dmp

Without having seen fully through your code IMO lines 47..50 have an improper setting of the parentheses, try changing to:
(for /F "delims=" %%g in ('svnlook youngest E:\svn\repositorios\!Line[%%i]!') do echo %%~g
) > E:\Backup\SVN\New\last_rev_!Line[%%i]!_new.data
An editor like Notepad++ helps to find/visualize corresponding pairs of parentheses.

Related

Batch script to pick filename from a text file and find the latest file

Scenario:
We have multiple releases of a product, and for each release, a folder is created in the main folder. A help file is modified in various releases. I have all the help file names listed in a text file.
I need a script to:
Take each file name from the filenames.txt file
Search for the file by that name in the entire directory (in all releases)
Find the latest file
Copy it to a specified folder
I took help from the various pieces of code I found on Stack Overflow, and combined them to get this code:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
echo.
FOR /F "usebackq delims=" %%a in ("filenames.txt") do (
SET "x=%%a"
ECHO '!x!'
SET FFPath=C:\SVN\nlbavwdocsvn\rep_doc_erpln\trunk\ERPLN
SET NewPath=C:\Lavanya\extracted
SET NewestDate=20160824
ECHO Recursively searching %FFPath%
FOR /F %%I in ('DIR %FFPath%\ !x! /a:-d /s /b') DO (
SET FullDate=%%~tI
ECHO %FFPath%
REM Set CurrDate to yyyymmdd format. Note: Will fail if regional settings changed.
SET CurrDate=!FullDate:~6,4!!FullDate:~0,2!!FullDate:~3,2!
If !CurrDate! gtr !NewestDate! (
SET NewestDate=!CurrDate!
SET NewestFile=%%~fI )
ECHO Copying %NewestFile% to %NewPath%
ECHO.
COPY /Y "%NewestFile%" "%NewPath%"
ECHO.
)
)
PAUSE
This code is not working. And I am unable to figure out the error.
Here is a script to search for the most recently modified file, using the wmic command to retrieve the last modification date/time in a locale-independent manner (e. g., 20160824115500.000000+060).
So for every file name read from the list file .\filenames.txt, the directory tree routed at directory C:\SVN\nlbavwdocsvn\rep_doc_erpln\trunk\ERPLN is searched for matching files recursively, and the respective modify date/time stamp is gathered. Due to its format, a simple greater-than (GTR) comparison can be done do determine whether or not it is a later point of time than a cached one; if the criterion is fulfilled, the cache is updated accordingly.
The upper-case REM and ECHO commands constitute placeholders only for the real action to be performed on the files. Extend the script there as you like. Variable !LASTFILE! holds the full path to each encountered file.
So here is the code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "LOCATION=C:\SVN\nlbavwdocsvn\rep_doc_erpln\trunk\ERPLN"
set "FILELIST=.\filenames.txt"
set "WMICPROP=LastModified" & rem // {CreationDate | LastAccessed | LastModified}
pushd "%LOCATION%" || exit /B 1
for /F "usebackq eol=| delims=" %%L in ("%FILELIST%") do (
set "LASTFILE="
set "LASTFAGE=00000000000000.000000+000"
for /F "eol=| delims=" %%F in ('dir /B /S /A:-D "%%~L"') do (
set "FILE=%%F"
setlocal EnableDelayedExpansion
set "FILE=!FILE:\=\\!"
for /F "tokens=2 delims==" %%J in ('
2^> nul wmic DataFile WHERE ^(Name^="!FILE!"^) GET %WMICPROP% /VALUE ^|^| ^
2^> nul wmic DataFile WHERE Name^="!FILE!" GET %WMICPROP% /VALUE
') do for /F %%I in ("%%J") do (
endlocal
set "FAGE=%%I"
setlocal EnableDelayedExpansion
if !FAGE! GTR !LASTFAGE! (
endlocal
set "LASTFILE=%%F"
set "LASTFAGE=%%I"
setlocal EnableDelayedExpansion
)
)
endlocal
)
if defined LASTFILE (
setlocal EnableDelayedExpansion
REM Do whatever you want with the file here...
ECHO Newest file: "!LASTFILE!"
endlocal
)
)
popd
endlocal
exit /B

Batch File: FOR /F doesn't work as expected

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

Renaming .txt files in bulk

I downloaded about 34000 books in .txt format from Project Gutenberg. Now I want to rename all of them by its content. For example every text file includes its "Title" and "Author's Name" so I want to rename all the text files on its "Title" and "Author's Name" by some commands.
I created a batch file. It runs but is not renaming the files. This is my code:
#echo off&setlocal
cd E:\Test
for /f "delims=" %%i in ('dir /a-d/b *.txt') do (
set "nname="
set "fname=%%~i"
for /f "usebackqskip=7delims=" %%f in ("%%~i") do if not defined nname
set "nname=%%f"
setlocal enabledelayedexpansion
set "nname=!nname:~0,40!"
echo rename "!fname!" "!nname!"
endlocal
)
You can use this as a base
#echo off
setlocal enableextensions disabledelayedexpansion
rem Change to source folder
pushd "e:\test" && (
rem Where the renamed files will be placed to avoid re-rename
if not exist renamed\ md renamed
rem For each input file
for %%f in (*.txt) do (
rem Retrieve the data from inside the file
set "author=" & set "title="
for /f "tokens=1,* delims=: " %%a in ('
findstr /b "Author: Title:" "%%~ff"
') do if not defined %%a set "%%a=%%b"
rem If the fields have been retrieved then do the rename
if defined author if defined title (
setlocal enabledelayedexpansion
for /f "delims=" %%a in ("!author! - !title!") do (
endlocal
echo move "%%~ff" "renamed\%%a%%~xf"
rem NOTE: operation is only echoed to console
rem if console output seems correct, then
rem remove the echo command
)
)
)
rem Done. Return to previous active directory
popd
)
Of course, filesystem has rules about what is allowed in a file name and, not knowing what kind of characters can be found, this code could and probably will fail to rename some files.
Your current script will just print the rename commands, not execute them. You should remove echo (after checking what it produces) in this line:
echo rename "!fname!" "!nname!"
Your script also has a few formatting issues. There should be spaces like this:
for /f "usebackq skip=7 delims=" %%f in ("%%~i") do
And there should be no newline just after:
if not defined nname

Batchfile: read last lines from logfiles and copy them to a new file

This is my first posting so if the format is not as it supposed to be please excuse me for this. (Suggestions for
improvement are welcome.)
I am trying to create a batchfile that will read last lines from logfiles and copy them to a new file.
Until now I have found here a way to read the last line.
Code would be something like:
for /f %%i in ('find /v /c "" ^< someFile.txt') do set /a lines=%%i
set /a startLine=%lines% - 1
more /e +%startLine% someFile.txt > lastLines.txt
The above code works for one file at a time. What I need is to read the last line from all files in a known list and add this line to a new .csv file.
I have been using the following code for getting the 4th entry in the logfiles but it returns every line of every logfile:
for /f %%x in (%list%) do for /f "delims=.txt, tokens=4" %%i in (%%x.txt) do echo %%x, %%i >> output.csv
What I would need is a sort of combination of both but I don't know how to combine them and make the complete last line be copied to the .csv file.
===
#Magoo:
Thanx for your reaction.
In every logfile can be 1 to >100 lines with comma separated information. Something like:
"LOGON,6-1-2015,12:43:39,USERNAME,HOSTNAME,,,,192.168.209.242,00:21:5A:2E:64:5E"
The last code with the 4th entry was used to get a list of all accounts that had logged in to the computers. This code gave me a very large list of all logon/logoff events on all computerlogs I checked in %list%.
In %list$ I had all the names of logfiles I wanted to be checked. This returned all lines.
For a new batchfile I need only the last logon/logoff entry and I want the whole last line.
So I have a .txt file with the hostnames of all computers I need to examine.
This .txt file will be read line by line via the variable %list%.
From every logfile I need only the last line copied to an output file.
===
I just tried the solution offered by JosefZ. Unfortunately this does not work for me yet. No lastlines are copied to the resultfile. In the code I removed the extra entry for possible lastlines for there are no empty lines in the logs, I also added an entry for the hostname I want to be available in the result. JosefZ had the filename there:
#ECHO OFF >NUL
#SETLOCAL enableextensions disabledelayedexpansion
type nul>output.csv
set "list=_listing.txt"
for /F "tokens=*" %%x in ('type "%list%"') do (
set "host=%%~x"
for /F "tokens=*" %%G in ('type "%%~x"') do set "lastline=%%G"
call :lline
)
:endlocal
#ENDLOCAL
goto :eof
:lline
set "filename=.\logs\%filename:&=^&%.txt"
echo %host%,%lastline%>>output.csv
goto :eof
The resultfile shows only the hostnames. I'll puzzle some more with this but all tips are welcome!
===
Got it!!!
#ECHO OFF >NUL
#SETLOCAL enableextensions disabledelayedexpansion
type nul>output.csv
set "list=_listing.txt"
for /F "tokens=*" %%x in ('type "%list%"') do (
set filename= :: *empty previous filename*
set lastline= :: *empty previous lastline*
set "host=%%~x"
set "filename=.\logs\%host%.txt" :: *creating the filename from path+hostname+extention*
for /F "tokens=*" %%G in ('type "%filename%"') do set "lastline=%%G"
call :lline
)
:endlocal
#ENDLOCAL
goto :eof
:lline
echo %host%,%lastline%>>output.csv
goto :eof
Your approach with line numbering could fail if a file has more trailing empty lines. Fortunately for /F loop ignores (does not iterate) empty lines; let's put to use this feature: in the script used next practices:
disabledelayedexpansion to allow ! in file names
set "list=_listing.txt" where the _listing.txt contains list of file names (full path and extension .txt including), one file name on one line: got by dir /b /s *.txt>_listing.txt
type nul>files\output.csv to empty the output file (optional)
set "lastline=!!!file empty!!!" to initialize variable %lastline%; could be set "lastline=" as well
call :lline to process variables %filename% and %lastline%
set "filename=%filename:&=^&%" to allow & in file names
The script is as follows:
#ECHO OFF >NUL
#SETLOCAL enableextensions disabledelayedexpansion
type nul>files\output.csv
set "list=_listing.txt"
for /F "tokens=*" %%x in ('type "%list%"') do (
set "filename=%%~x"
set "lastline=!!!file empty!!!"
rem the whole line
for /F "tokens=*" %%G in ('type "%%~x"') do set "lastline=%%G"
rem the fourth token only
rem for /F "tokens=4" %%G in ('type "%%~x"') do set "lastline=%%G"
call :lline
)
:endlocal
#ENDLOCAL
goto :eof
:lline
set "filename=%filename:&=^&%"
echo %filename% %lastline%
rem >>files\output.csv
goto :eof
Sample _listing.txt file:
d:\bat\files\1exclam!ation.txt
d:\bat\files\2exc!lam!ation.txt
d:\bat\files\11per%cent.txt
d:\bat\files\12per%cent%.txt
d:\bat\files\17per%Gcent.txt
d:\bat\files\18per%%Gcent.txt
d:\bat\files\21ampers&nd.txt
d:\bat\files\22ampers&&nd.txt
Output:
d:\bat>lastlines
d:\bat\files\1exclam!ation.txt 0 15.01.2015 1:52:28.48 -15072 20465
d:\bat\files\2exc!lam!ation.txt 6 15.01.2015 1:52:28.50 3250 16741
d:\bat\files\11per%cent.txt -8 15.01.2015 1:52:28.50 -3692 27910
d:\bat\files\12per%cent%.txt !!!file empty!!!
d:\bat\files\17per%Gcent.txt 0 15.01.2015 1:52:28.56 14508 12374
d:\bat\files\18per%%Gcent.txt 1 15.01.2015 1:52:28.56 30540 26959
d:\bat\files\21ampers&nd.txt 15.01.2015 1:22:50.18
d:\bat\files\22ampers&&nd.txt 15.01.2015 1:22:50.18
Honestly, all that ballast is for (possibly) trailing empty lines in files and for (possibly) ! and & in file names only; all could be done with
for /f %%x in (%list%) do for /f "skip=%startLine% tokens=4" %%i in (%%x) do echo %%x, %%i >> output.csv
You should use a simple FOR to iterate a list of values, not FOR /F.
Something like the following should work:
#echo off
setlocal enableDelayedExpansion
>>output.csv (
for %%F in (
"file1.log"
"file2.log"
"file3.log"
etc.
) do (
for /f %%A in ('find /v /c "" <%%F') do set /a skip=%%A-1
more +!skip! %%F
)
)
The quotes around the file names are there in case you get a name with spaces.
You could use your LIST variable if it looks something like
set LIST="file1.log" "file2.log" "file3.log" etc.
#echo off
setlocal enableDelayedExpansion
set LIST="file1.log" "file2.log" "file3.log" etc.
>>output.csv (
for %%F in (%LIST%) do (
for /f %%A in ('find /v /c "" <%%F') do set /a skip=%%A-1
more +!skip! %%F
)
)
If any of your file names contain the ! character, then you must toggle delayed expansion ON and OFF within your loop. Otherwise the delayed expansion will corrupt the names when %%F is expanded.
#echo off
setlocal disableDelayedExpansion
set LIST="file1.log" "file2.log" "file3.log" etc.
>>output.csv (
for %%F in (%LIST%) do (
for /f %%A in ('find /v /c "" <%%F') do set /a skip=%%A-1
setlocal enableDelayedExpansion
more +!skip! %%F
endlocal
)
)

How to replace Strings in Windows Batch file

I would like to replace the following String in a file:
android:versionName="anyStringHere" >
*anyStringHere represents any possible string
With:
android:versionName="1.04.008" >
How would I do this in a clean, reusable way, and preserve the new lines, tabs, and indentation in the file?
Not even close to the fastest option, and not 100% bulletproof, but this is pure batch and will handle spacing and indentation while do the replacement.
#echo off
setlocal enableextensions disabledelayedexpansion
rem File to process
set "file=data.txt"
rem How to find lines
set "match=public static String CONST = \"abc\";"
rem String to replace and replacement
set "findStr=abc"
set "replaceStr=def"
rem temporary file to work with lines
set "tempFile=%temp%\repl.tmp"
rem All the output goes into the temporary file
(
rem Process input file extracting non matching lines
for /f tokens^=^1^*^ delims^=^:^ eol^= %%a in ('findstr /n /v /c:"%match%" ^< "%file%"') do (
set /a "n=1000000+%%a"
setlocal enabledelayedexpansion
< nul set /p "n=!n!"
endlocal
echo :%%b
)
rem Process input file extrancting matching lines and changing strings
for /f tokens^=^1^*^ delims^=^:^ eol^= %%a in ('findstr /n /c:"%match%" ^< "%file%"') do (
set /a "n=1000000+%%a"
set "data=%%b"
setlocal enabledelayedexpansion
set "data=!data:%findStr%=%replaceStr%!"
echo !n!:!data!
endlocal
)
)> "%tempFile%"
rem Sort the output file to get the final file
(for /f tokens^=^1^*^ delims^=^:^ eol^= %%a in ('sort "%tempFile%"') do (
if "%%b"=="" (
echo.
) else (
echo %%b
)
)) > "%file%.repl"
This is the simplest way to do this that I could come up with. It takes a String and searches for it in a file, then replaces the entire line that contains the string. It won't only replace parts of a line, which can be done with a bit more effort.
#echo off
:: file containing string to replace
set file=test.txt
:: string to replace in file
set searchString=line 4
:: string to write to file
set repString=line 4 edited
setLocal enableDelayedExpansion
set count=0
if not exist %file% echo cannot find file - %file% & goto :EOF
:: Search for string - and get it's line number
for /F "delims=:" %%a in ('findstr /N /I /C:"%searchString%" "%file%"') do set searchLine=%%a
if not defined searchLine echo cannot find string - %searchString% - in file - %file% & goto :EOF
:: Read file into variables - by line number
for /F "delims=~!" %%b in ('type %file%') do (
set /a count=!count!+1
set line!count!=%%b
)
:: Edit the one line
set line%searchLine%=%repString%
:: Empty file and write new contents
del %file%
for /L %%c in (1,1,!count!) do echo !line%%c!>>%file%
pause
You can change the echo on the last for loop to output to a different file, maybe %file%.new or something, and then remove the del command.
This is a robust solution that retains all formatting. It uses a helper batch file called repl.bat - download from: https://www.dropbox.com/s/qidqwztmetbvklt/repl.bat
Place repl.bat in the same folder as the batch file or in a folder that is on the path.
type "file.txt" | repl "(public static String CONST = \q).*(\q.*)" "$1def$2" x >"newfile.txt"
I found that using sed was the cleanest solution
http://gnuwin32.sourceforge.net/packages/sed.htm
sed "s/android:versionName=\".*\" >/android:versionName=\"%NEW_VERSION%\" >/g" %ORIG_FILE_NAME% > %TEMP_FILE_NAME%
#move /Y %TEMP_FILE_NAME% %ORIG_FILE_NAME% >nul

Resources