I am looking at creating a batch file that extracts information out of a txt file from the last 3 months of log files, and out puts with the following information:
Computer name taken from file Path:
\\Server\e$\Users\\**COMPUTER_NAME**\path\search_file.txt
Search for total number of occurrences in a file (Nice to have - Not MUST)
Time of occurrence:
File being searched has a format of this when found:
09:24:08:17 (WS:PED:RunRequest)
Response: (0) None
Error : -2
So...
COMPUTER_NAME
Number of occurrences found
Time of occurrence i.e. 09:24:08:17
I have this as a start:
#echo off
echo.
echo Searching for all Error : -2...
setlocal enabledelayedexpansion
for %%a in (\\Sc0320svr0001\e$\Users\SC0320POS0003\E2ELOGS\ped_20140812_092355.dbg) do
(
set found=false
for /f "skip=2 tokens=*" %%b in ('find "Error : -2" "%%a"') do (
if "!found!"=="false" (
echo %%b >>output.txt
set found=true
)
)
)
With this I extract only the "Error : -2", and there could be MULTIPLE instances within.
Found the batch to do a count number:
#find /c /i "Error : -2" "\\Sc0320svr0001\e$\Users\SC0320POS0003\E2ELOGS\*.dbg" >>output.txt
However ONLY looking to output if greater than zero.
Portion of the file:
09:23:55:68 (WS:PED:OpenHandler)
Exit
09:23:55:76 (WS:PED:RunRequest)
Request: (1) Check PED status
09:23:55:86 (WS:PED:Write)
Data: 97
09:24:08:08 (WS:PED:Write)
Error: 30
09:24:08:17 (WS:PED:RunRequest)
Response: (0) None
Error : -2
Message :
Receipt :
This processes only one file...Check if it is doing the job:
#echo off
setlocal enableDelayedExpansion
set file_txt=apple.txt
set "current_line="
set "prev_line="
set "prev_prev_line="
set counter=0
for /f "tokens=* delims=" %%a in (%file_txt%) do (
rem echo -%%a-
if defined prev_line (
set prev_prev_line=!prev_line!
)
if defined current_line (
set prev_line=!current_line!
)
set "current_line=%%~a"
if "!current_line: =!" EQU "Error:-2" (
set /a counter=counter+1
echo(
echo Error -2 found
echo in %file_txt%
echo time is !prev_prev_line!
echo responces !prev_line!
echo(
)
)
echo total count %counter%
endlocal
EDIT. process multiple files
#echo off
setlocal enableDelayedExpansion
:: separate the file names with ;
set files_to_process=apple.txt;banana.txt;pear.txt
set "current_line="
set "prev_line="
set "prev_prev_line="
set counter=0
for %%f in (%files_to_process%) do (
for /f "tokens=* delims=" %%a in (%file_txt%) do (
rem echo -%%a-
if defined prev_line (
set prev_prev_line=!prev_line!
)
if defined current_line (
set prev_line=!current_line!
)
set "current_line=%%~a"
if "!current_line: =!" EQU "Error:-2" (
set /a counter=counter+1
echo(
echo Error -2 found
echo in %file_txt%
echo time is !prev_prev_line!
echo responces !prev_line!
echo(
)
)
)
echo total count %counter%
endlocal
Related
I am trying to search through a text file for keywords, then insert a number of lines after a specific line/keyword (not end of file).
My code can find the keywords, however I am struggling to add the lines. My code adds the line to the end of the file, so the bit I need help with is after :ADD THE TEXT.
myfile.text looks like:
QFU;
text2;
LastUpdate=20180323;
text3;
I would like to add a list of static lines after LastUpdate, which makes the file look like:
QFU;
text2;
LastUpdate=20180323;
Inserted text1
Inserted text2
text3;
This is my code:
#echo
SET /A COND1=0
for /F "tokens=*" %%i in (myfile.txt) do call :process %%i
goto thenextstep
:process
set VAR1=%1
IF "%VAR1%"=="QFU" SET /A COND1=1
IF "%VAR1%"=="QFU" (
msg * "QFU line found !!"
)
:If QFU line is found then look for Last update
IF "%COND1%"=="1" IF "%VAR1%"=="LastUpdate" (
msg * "LastUpdate line found !!"
:ADD THE TEXT
echo. text to be added>>myfile.txt
:reset COND1 to 0
set /A COND1=0
)
#echo off
setlocal enabledelayedexpansion
call :get_insert_index
if not defined index (
>&2 echo index not defined.
exit /b 1
)
set "i=0"
(
for /f "tokens=*" %%A in (myfile.txt) do (
set /a "i+=1"
echo %%A
for %%B in (%index%) do if !i! equ %%B (
echo --- INSERT
)
)
) > myupdate.txt
exit /b
:get_insert_index
setlocal enabledelayedexpansion
set "i=0"
set "qfu="
set "total="
for /f "tokens=*" %%A in (myfile.txt) do (
set /a i+=1
set "line=%%~A"
if "%%~A" == "QFU;" (
set /a "qfu=!i! + 1"
) else if "!line:~,11!" == "LastUpdate=" (
if defined qfu (
if !i! gtr !qfu! (
if defined total (set total=!total! !i!) else set total=!i!
set "qfu="
)
)
)
)
endlocal & set "index=%total%"
exit /b
This will insert text after the 1st line starting with LastUpdate=,
after the line of QFU;, but not the line starting with LastUpdate=
which is the next line after QFU;.
The label :get_insert_index is called and uses a for loop
to read myfile.txt to get the line index of LastUpdate=
mentioned in the above paragraph.
The variable qfu stores the line index + 1 of QFU; so
LastUpdate= cannot be matched on the next line.
If gfu and LastUpdate= is found and the line index is
greater then gfu, then the line index is appended to total.
qfu is undefined to avoid further matches to LastUpdate=
until QFU; is matched again.
The loop will end and the global variable index is set the
value of total. The label returns control back to the caller.
index is checked if defined at the top of the script after
the call of the label.
The top for loop reads myfile.txt and echoes each line read.
The nested for loop checks the index variable to match the
current line index and if equal, will echo the new text.
The echoes are redirected to myupdate.txt.
Used substitution of "!line:~,11!" so view set /? for help.
Used enabledelayedexpansion so view setlocal /? for help.
Text using ! may find ! being interpreted as a variable
so avoid using !.
Used gtr which can be viewed in if /?. gtr is
"Greater than".
Alternative to avoid creation of an index:
#echo off
setlocal enabledelayedexpansion
set "i=0"
set "gfu="
for /f "tokens=*" %%A in (myfile.txt) do (
set /a i+=1
set "line=%%~A"
>> myupdate.txt echo(%%A
if "%%~A" == "QFU;" (
set /a "qfu=!i! + 1"
) else if "!line:~,11!" == "LastUpdate=" (
if defined qfu (
if !i! gtr !qfu! (
>> myupdate.txt echo --- INSERT
set "qfu="
)
)
)
)
exit /b
>> myupdate.txt echo(%%A writes each line.
>> myupdate.txt echo --- INSERT writes new line to insert.
If system memory permits based on file size, this is much faster:
#echo off
setlocal enabledelayedexpansion
set "i=0"
set "gfu="
(
for /f "tokens=*" %%A in (myfile.txt) do (
set /a i+=1
set "line=%%~A"
echo(%%A
if "%%~A" == "QFU;" (
set /a "qfu=!i! + 1"
) else if "!line:~,11!" == "LastUpdate=" (
if defined qfu (
if !i! gtr !qfu! (
echo --- INSERT
set "qfu="
)
)
)
)
) > myupdate.txt
exit /b
Used on 2.74 MB file, Time reduced from 70s to 21s. The write handle to myupdate.txt remains open for the entire loop, thus the write is cached.
Suppose I have a text file like this
node1.log
node2.log
node3.log
node4.log etc...
I want to read each line by line and execute
alan.exe node1.log node2.log
alan.exe node3.log node4.log
etc..
What is the best way to accomplish this?
#echo off
setlocal EnableDelayedExpansion
for /F "delims=" %%a in (file.txt) do (
if not defined line (
set "line=%%a"
) else (
ECHO alan.exe !line! %%a
set "line="
)
)
Give this a try. File.txt will have your log file names.
#echo off
setlocal enabledelayedexpansion
FOR /F "delims=" %%G IN ('find /c /v "" ^<file.txt') DO SET NUM=%%G
SET /A NUM=NUM / 2
< file.txt (
FOR /L %%G IN (1,1,%NUM%) DO (
SET /P LINE1=
SET /P LINE2=
echo mypgm.exe !LINE1! !LINE2!
)
)
pause
Output
mypgm.exe node1.log node2.log
mypgm.exe node3.log node4.log
mypgm.exe node5.log node6.log
Press any key to continue . . .
Remove the word echo and replace mypgm.exe with the program you want to run. The echo is just in there for the proof of concept.
Like this:
#echo off
setlocal enabledelayedexpansion
set args=
set n=2
for /f "tokens=*" %%x in (file.txt) do (
set args=!args! %%x
set /a n -= 1
if !n! EQU 0 (
alan !args!
set args=
set n=2
)
)
I have a program to search drives for a specific file. The only problem is is that i wont know what drive it is on. The problem occurs when it searches a drive for a file that isn't there is there a way to go on to the next drive after say like 10 seconds. Heres my code so far
#echo off
setlocal EnableDelayedExpansion
set count=1
for /f "skip=1" %%a in ('wmic logicaldisk get caption') do (
set drive!count!=%%a
set /a count+=1
)
set "gh=!drive1!"
::Change this to do whatever with the variables
set "fh=!drive2!"
set "hh=!drive3!"
set "jh=!drive4!"
For /R %gh%\ %%G IN (*.ut2) do set jk="%%~dpG"
if defined jk (
echo %jk%
) else (
goto next
)
for /r %jk% %%a in (*) do if "%%~nxa"=="CTF-Hydro-16-2k3.ut2" set k=%%~dpnxa
if defined k (
echo %k% found
pause
cls
echo You have it
goto end
) else (
echo Map not found
copy %CD:~0,3%\Unrealmap\CTF-Hydro-16-2k3.ut2 %jk%
goto end
)
:next
For /R %fh%\ %%G IN (*.ut2) do set ht="%%~dpG"
if defined ht (
echo %ht%
) else (
goto there
)
for /r %ht% %%a in (*) do if "%%~nxa"=="CTF-Hydro-16-2k3.ut2" set m=%%~dpnxa
if defined k (
echo %m% found
pause
cls
echo You have it
goto end
) else (
echo Map not found
copy %CD:~0,3%\Unrealmap\CTF-Hydro-16-2k3.ut2 %jk%
goto end
:there
:end
cls
echo done
pause
#echo off
for /f "skip=1" %%D in ('wmic logicaldisk get caption') do (
for /r "%%D\\" %%G IN (*.ut2) do (
echo %%~dpG
if exist "%%~dpGCTF-Hydro-16-2k3.ut2" (
echo Found the map.
goto end
) else (
echo Map not found, copying
copy %CD:~0,3%\Unrealmap\CTF-Hydro-16-2k3.ut2 "%%~dpG"
goto end
)
)
)
:end
pause
Try next approach:
#ECHO OFF >NUL
SETLOCAL enableextensions
set /A "ii=0"
for /f "skip=1" %%D in ('
wmic logicaldisk get caption
') do for /F %%d in ("%%D") do (
echo searching %%d
for /F "delims=" %%G IN ('dir /B /S "%%d\CTF-Hydro-16-2k3.ut2" 2^>nul') do (
set /A "ii+=1"
set "k=%%G"
rem remove 'rem' from next line to discontinue searching
rem goto :testfound
)
TIMEOUT /T 10 /NOBREAK >NUL
)
:testfound
if %ii% EQU 0 (
echo Map not found
) else (
echo Map found %ii% times: last one "%k%"
)
Here the for loops against wmic command are
%%D to retrieve the caption value;
%%d to remove the ending carriage return in the value returned: wmic behaviour: each output line ends with 0x0D0D0A (<CR><CR><LF>) instead of common 0x0D0A (<CR><LF>).
See Dave Benham's WMIC and FOR /F: A fix for the trailing <CR> problem
Another eventuality: parse
wmic datafile where "Extension='ut2' and FileName='CTF-Hydro-16-2k3'" get Name 2>NUL
I am new to using batch files so could someone please help me split a string i am getting from a file.
I am using %USERPROFILE% to get my string.
The string is: "C:\Users\nicholas"
I would like to keep the C:\ part, but get rid of the \Users\nicholas part.
for /f "tokens=2 delims=\" %A in ('set userprofile') do echo %A\
See for /?
Also
echo %userprofile:~0,3%
If you carefully read the output of set /?, you'll find the answer:
May also specify substrings for an expansion.
%PATH:~10,5%
would expand the PATH environment variable, and then use only the 5
characters that begin at the 11th (offset 10) character of the expanded
result.
So, you can use something like this to get the first 3 characters of your string:
> echo %userprofile:~0,3%
C:\
I As you need the drive where where the users are located you can use directly
%systemdrive% variable - this is the drive where the windows is installed
II the easiest way to get a drive from path:
for %%a in ("%userprofile%") do echo %%~da\
%~da - expands a path to its drive only
III over-complicated but powerful way (split function that can be used for a different things):
#echo off
call :split "%userprofile%" "\" 1 drive
echo %drive%\
goto :eof
:split [%1 - string to be splitted;%2 - split by;%3 - possition to get; %4 - if defined will store the result in variable with same name]
::http://ss64.org/viewtopic.php?id=1687
setlocal EnableDelayedExpansion
set "string=%~2%~1"
set "splitter=%~2"
set /a position=%~3
set LF=^
rem ** Two empty lines are required
echo off
for %%L in ("!LF!") DO (
for /f "delims=" %%R in ("!splitter!") do (
set "var=!string:%%~R%%~R=%%~L!"
set "var=!var:%%~R=%%~L!"
if "!var!" EQU "!string!" (
echo "%~1" does not contain "!splitter!" >&2
exit /B 1
)
)
)
if "!var!" equ "" (
endlocal & if "%~4" NEQ "" ( set "%~4=")
)
if !position! LEQ 0 ( set "_skip=" ) else (set "_skip=skip=%position%")
for /f "eol= %_skip% delims=" %%P in (""!var!"") DO (
if "%%~P" neq "" (
set "part=%%~P"
goto :end_for
)
)
set "part="
:end_for
if not defined part (
endlocal
echo Index Out Of Bound >&2
exit /B 2
)
endlocal & if "%~4" NEQ "" (set %~4=%part%) else echo %part%
exit /b 0
Good Afternoon!
Long time reader, first time poster! I have been having a lovely time trying to modify a working batch file to account for variability. The situation is that I have a variable-size text document that normally would be able to be split into sections of 252 lines. The code below worked like a champ:
#echo off & setlocal EnableDelayedExpansion
set param=%*
if not defined param (
echo.
echo. Usage: batchsplit [device:][pathname]filename
goto :EOF
)
set param=%param:"=%
if not exist "%param%" (
echo.
echo. File "%param%" not found
goto :EOF
)
for %%j in ("%param%") do (
set name=%%~dpnj
set ext=%%~xj
)
for /F %%j in ('type "%param%" ^| find /V /C ""') do set Full=%%j
set /A Split=%Full%/252
for /L %%G in (1,1,%Split%) do type nul > "%name%_%%G%.new"
set X=1
set N=1
set Q=1
set limit = 252
for /F "tokens=1* delims=]" %%j in ('type "%param%" ^| find /V /N ""') do (
set /A N+=1
set /A Q+=1
echo.%%k>> "%name%_!X!%.new"
if !Q! gtr 252 (
set /A X+=1
set /A Q=1
) else if !N! gtr Full (goto theend
)
)
:theend
echo split into %split% files with 252 lines each
rem pause
However, there were some changes to the formatting of the text, and now instead of four pages of 63 lines per split file, it can be completely variable. The only constant is this final line, which precedes the remaining space for a 63 line page:
ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________
Note that there is a single space in front of it, as well as multiple spaces, a colon, and underscore characters. Being the meathead that I am, I thought I could insert an if-then statement into the for loop to trigger the batch to split to the next page. However, I could be further from that right now. This is the code I have been smashing my head with:
rem #echo off & setlocal EnableDelayedExpansion
setlocal EnableDelayedExpansion
set param=%*
if not defined param (
echo.
echo. Usage: textsplit [device:][pathname]filename
goto :EOF
)
set param=%param:"=%
if not exist "%param%" (
echo.
echo. File "%param%" not found
goto :EOF
)
for %%j in ("%param%") do (
set Name=%%~dpnj
set ext=%%~xj
)
for /F %%j in ('type "%param%" ^| find /V /C ""') do set Full=%%j
set stopvar= ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________
set Split=1
echo %stopvar%
set X=1
type nul > "%name%_!X!%.new"
set N=1
set Q=1
set S=0
set L=63
for /F "tokens=1* delims=]" %%j in ('type "%param%" ^| find /V /N ""') do (
set /A N+=1
echo %N%
set /A Q+=1
echo %Q%
echo.%%k>> "%name%_!X!%.new"
if ["%%k%" == "!stopvar!"] (
set /A S+=1
)
if !Q! gtr !L! (
if !S! == 1 (
set /A X+=1
set /A Q=1
type nul > "%name%_!X!%.new"
set /A Split+=1
set S=0
)
else set /A L+=63
else if !N! gtr Full goto theend
)
:theend
echo Split into %split% files!
pause
The premise is that every 63 lines, the stop variable (S) is checked. If it is off (0) then the batch will continue to write for another 63 lines (one page). If the stopvar matches the line that is being read by the for loop, S becomes 1. When the program checks again, it will create a new file and begin writing to that new file. Right now, based on turning off #echo off the hangup is at the for loop. See below:
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>rrtextsplit texttest.txt
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>rem #echo off & setlocal Enabl
eDelayedExpansion
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>setlocal EnableDelayedExpansio
n
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set param=texttest.txt
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>if not defined param (
echo.
echo. Usage: rrtextsplit [device:][pathname]filename
goto :EOF
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set param=texttest.txt
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>if not exist "texttest.txt" (
echo.
echo. File "texttest.txt" not found
goto :EOF
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>for %j in ("texttest.txt") do
(
set Name=%~dpnj
set ext=%~xj
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>(
set Name=C:\Users\theangryasiancp\Desktop\TEXT_Split_Test\texttest
set ext=.txt
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>for /F %j in ('type "texttest.
txt" | find /V /C ""') do set Full=%j
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set Full=567
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set stopvar= ON THIS FORM IS C
OMPLETE AND CORRECT AS NOTED:___________________
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set Split=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>echo ON THIS FORM IS COMPLETE
AND CORRECT AS NOTED:___________________
ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set X=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>type nul 1>"C:\Users\theangry
asiancp\Desktop\RRRR_Split_Test\texttest_!X!.new"
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set N=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set Q=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set S=0
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set L=63
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>
What are your thoughts? Where am I going wrong with the batch? I wish I could use something different, but alas I cannot, for internal company reasons. Thanks for your help!
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "name=q23396663"
SET "ext=.txt"
SET /a pagelength=10
SET "targetstring= ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________"
SET /a filenum=0
SET /a linecount=pagelength + 1
FOR /f "tokens=1*delims=]" %%a IN (
'find /v /n "" "%name%%ext%"') DO (
IF !linecount! GEQ %pagelength% (
SET /a linecount=0
SET /a filenum+=1
)
>>U:\%name%_!filenum!.new ECHO(%%b
IF "%%b"=="%targetstring%" SET /a linecount=pagelength
SET /a linecount+=1
)
GOTO :EOF
For testing purposes, I set up a file q23396663.txt containing your trigger data. I've left the destination directory as U:\ which suits me, and the pagelength at 10 which makes my testing easier.
#echo off
setlocal EnableDelayedExpansion
REM ------------------THIS SECTION SPECIFIES THE FILE-------------------------
set param=%*
if not defined param (
echo.
echo. Usage: filesplit [device:][pathname]filename
goto :EOF
)
set param=%param:"=%
if not exist "%param%" (
echo.
echo. File "%param%" not found
GOTO :EOF
)
for %%j in ("%param%") do (
set name=%%~dpnj
set ext=%%~xj
)
ECHO SPLITTING %name%.%ext% .................
REM ----------------THIS SECTION SETS THE VARIABLES---------------------------
set "trigger= ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________"
set /a pagelength=63
set /a filenum=0
set split=1
set /a linecount=pagelength
set stopvar=0
REM ------------------THIS SECTION IS THE FOR LOOP----------------------------
FOR /f "skip=2 tokens=1* delims=]" %%a IN (
'find /v /n "" "%name%%ext%"') DO (
SET /a linecount-=1
IF !linecount! LEQ 0 (
IF !stopvar! EQU 1 (
SET /a "linecount=pagelength"
SET /a filenum+=1
SET /a split+=1
SET /a stopvar-=1
) else set /a "linecount=pagelength"
)
echo.%%b>> "%name%_!filenum!.new"
IF "%%b"=="%trigger%" (
set /a "stopvar+=1"
REM THIS TRIGGERS TO CHANGE OUTPUT
set /a linecount+=1
REM THIS WILL ADJUST THE OUTPUT EOF
)
)
REM ----------------THIS SECTION ENDS THE FOR LOOP----------------------------
ECHO Split into %split% files!
ping 1.1.1.1 -n 1 -w 2500 > nul
REM THIS PAUSES THE BATCH FOR A SEC
As I posted in the comment above, this is just a variation of the first answer that accounts for blank spaces if they are needed to keep the output files from having unnecessary whitespace on top. This is especially helpful when a print manager is just spitting out whitespace until the end of the page before starting the next part instead of going straight to the next portion.