I'm trying to merge files with logic, to fill in missing data. I'm
having issues with if errorlevel
#echo off
SETLOCAL enableDelayedExpansion
del /q porttemp.csv
del /q database.csv
rem CMD BATCH-FILE Trying to merge files with logic to fill missing data.
rem * building a flat database ?
rem *** Reading temp3.csv looking for match in temp4.csv, ie 34/0/23
rem *** if not found trying to add "blank" to output file
echo ********* Phase 1 begin *******
:part1
FOR /F "tokens=1,2,3,4* delims=," %%a IN (temp3.csv) do (
rem parse thru temp3.csv
echo LOOP 1 - %%a,%%b,%%c,%%d
for /F "tokens=1,2* delims=, " %%M in (temp4.csv) do (
rem is %%a found in temp4.csv
rem if true output %%a,%%b,%%c,%%M
rem if false output %%a,%%b,%%c,blank
findstr %%a temp4.csv
if /I ERRORLEVEL EQU 0 (echo %%a,%%b,%%c,%%M >> porttemp.csv) ELSE (echo %%a,%%b,%%c,blank >> porttemp.csv)
echo Loop 2 - debug output - %ERRORLEVEL% -%%a,%%b,%%c vs %%M,%%N
pause
)
)
type porttemp.csv
temp3.csv contains:
Gi-34/0/10_,lpu,w-3-018ch1swA2p19_lag Gi-34/0/11_,lpu,prodca1_lan_sec
Gi-34/0/12_,lpu,prodca2_lan_sec Gi-34/0/13_,lpd, Gi-34/0/14_,lpd,
Gi-34/0/15_,lpd, Gi-34/0/16_,lpd, Gi-34/0/17_,lpd,
Gi-34/0/18_,lpu,aix_to_hmc Gi-34/0/19_,lpu,prodcafl1_lan_sec
Gi-34/0/02_,lpu,w-3-016ch1swA2p19_lag
Gi-34/0/20_,lpu,prodcafl2_lan_sec Gi-34/0/21_,lpu,prodcafl3_lan_sec
Gi-34/0/22_,lpu,prodcafl4_lan_sec Gi-34/0/24_,lpd,
Gi-34/0/25_,lpu,CHARONHOST2_DARLA Gi-34/0/26_,lpu,Centera_c001n03
Gi-34/0/27_,lpu,Centera_c001n01 Gi-34/0/28_,lpu,Centera_c001n02
Gi-34/0/29_,lpu,Centera_c001n04 Gi-34/0/03_,lpu,w-3-016ch2swA1p19_lag
Gi-34/0/30_,lpu,Centera_c002n03 Gi-34/0/31_,lpu,Centera_c002n02
Gi-34/0/32_,lpu,Centera_c002n04 Gi-34/0/33_,lpu,Centera_c002n01
Gi-34/0/34_,lpu,CHARONHOST2 Gi-34/0/35_,lpd, Gi-34/0/36_,lpd,
Gi-34/0/37_,lpd, Gi-34/0/38_,lpu,TMC_Flex7_cmm2
Gi-34/0/39_,lpu,TMC-TPC_Sec
temp4.csv file contains:
98be:947e:257c,Gi-34/0/18_ 5cf3:fc39:a194,Gi-34/0/23_
aa00:0400:64a4,Gi-34/0/25_ d43d:7e7d:8e4e,Gi-34/0/26_
d43d:7ec1:f280,Gi-34/0/27_ d43d:7e7d:9770,Gi-34/0/28_
Here's a version, similar to LotPings but with anything unnecessary for the actual end goal removed:
#Echo Off
SetLocal EnableDelayedExpansion
(For /F "UseBackQ Tokens=1-3 Delims=," %%A In ("temp3.csv") Do (Set "_=blank"
For /F "Delims=," %%D In ('Find /I "%%A "^<"temp4.csv"') Do Set "_=%%D"
Echo=%%A,%%B,%%C,!_!))>porttemp.csv
Type porttemp.csv
Remove the word blank on line 3 if you really do want nothing to be output after the comma.
IMHO you do over complicate things. If you set a var prior searching temp4.csv to blank and only process finds in temp4.csv there is no need for an if:
#echo off
SETLOCAL enableDelayedExpansion
del /q porttemp.csv
del /q database.csv
rem CMD BATCH-FILE Trying to merge files with logic to fill missing data.
rem * building a flat database ?
rem *** Reading temp3.csv looking for match in temp4.csv, ie 34/0/23
rem *** if not found trying to add "blank" to output file
echo ********* Phase 1 begin *******
:part1
FOR /F "tokens=1-4* delims=," %%a IN (temp3.csv) do (
rem parse thru temp3.csv
echo LOOP 1 - %%a,%%b,%%c,%%d
Set "BlankorM="
for /F "tokens=1,2* delims=, " %%M in (
'Findstr /I "%%a" temp4.csv'
) do Set "BlankorM=%%M"
echo %%a,%%b,%%c,!BlankorM! >> porttemp.csv
)
type porttemp.csv
I have a series of text files each named the same in sub-folders of a certain directory
ac.txt files have the following structure :
---
some text
---
[lights]
---
some text
---
[GetEngineData]
---
some text
---
I want to get all those lines in between strings [lights] and [GetEngineData] (including those start [lights] and end [GetEngineData] lines) in one single output file called lights.txt with a blank space in between those coming from each text file.
I coded the following batch yet it is of no avail so far :
#ECHO OFF
for /r %%a in ('find /n "[lights]"^<(ac.txt) ') do set /a start=%%a
for /r %%a in ('find /n "[GeneralEngineData]"^<(ac.txt) ') do set /a end=%%a
(
for /r %%a in ('find /n /v ""^<(ac.txt) ') do (
IF %%a geq %start% IF %%f leq %end% ECHO(%%b
)
)>lights.txt
Here's a way to do it. Might not be the most efficient but it seems to do the job just fine. The code loops through all subfolders and picks up all .TXT files. It then parses each line of each file, marking the beginning/end of each block using the [lights] and [GeneralEngineData] tokens and then outputs everything to res.txt in the same folder where the batch file is stored.
#ECHO OFF
Setlocal EnableDelayedExpansion
if exist res.txt del res.txt
set inblock=0
for /r . %%a in (*.txt) do (
set fname=%%a
for /f "tokens=1* delims=]" %%b in ('type "!fname!" ^| find /n /v ""') do (
if /i *%%c*==*[lights]* set inblock=1
if !inblock!==1 (
if *%%c*==** (echo.) else (echo %%c)
if /i *%%c*==*[GetEngineData]* set inblock=0
)
)
echo.
) >> res.txt
set fname=
set inblock=
type res.txt
Using the following code I am able to create a list of folders in a directory -
Setlocal EnableDelayedExpansion
set /p pattern=Enter Search Term:
echo.
dir /b /A:D %pattern%*
For example, if the user inputs con, the result may be
-construction1
-construction2
-construction_Docs
etc.
I would like to be able to attach a value to each item eg.
1_Construction1
2_Construction_Docs
etc.
Am I correcting in thinking that I would have to output the initial list I created to a .txt and then read and attach a variable to every line?
The end result would be a user being able to select one of the items based on the number we attach to it, and then have further actions being taken on that item.
dir /b /A:D %pattern%*|find /n /v ""
would yield
[1]construction1
[2]construction2
[3]construction_Docs
or
dir /b /A:D %pattern%*|findstr /n /v ":"
would yield
1:construction1
2:construction2
3:construction_Docs
You could then try
set /a max=0
for /f "delims=:" %%a in ('dir /b /A:D %pattern%*^|findstr /n /v ":" 2^>nul') do set /a max=%%a
which would set max to 0 if none found or the maximum number
The ^ tells batch that the pipe/> is part of the command to be executed
2>nul suppresses error messages in the case of no matches found
It's then a simple matter of
if %max%==0 echo none found&goto askagain
set /p "selection=Please choose [1..%max%] ? "
for /f "tokens=1*delims=:" %%a in ('dir /b /A:D "%pattern%*"^|findstr /n /v ":" 2^>nul') do if "%%a"=="%selection%" set "dirselected=%%b"&goto found
echo %selection% is invalid
goto askagain
:found
echo %dirselected% selected.
to make a complete job.
This task is relatively simple to achieve if you use the right tools, like an array:
#echo off
setlocal EnableDelayedExpansion
set /P "pattern=Enter Search Term: "
echo/
rem Get the folders, store they in the array and show the menu
set "num=0"
for /D %%f in (%pattern%*) do (
set /A num+=1
set "folder[!num!]=%%f"
echo !num!- %%f
)
if %num% equ 0 echo No folders found & goto :EOF
echo/
:selectFolder
set /P "num=Enter the desired folder: "
echo/
if not defined folder[%num%] goto selectFolder
set "item=!folder[%num%]!"
echo Folder selected: %item%
For further details on array management in Batch files, see this post.
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
)
)
I have recently started to learn how to make batch files. I have a folder that contains bunch of internet related log files. When I run the .cmd file (located in the same folder) I want it to be able to find out how many log files are in the folder and make a numbered menu from it. So lets say there are twenty files in the folder, then the user must be able to select from 1 to 21. 21 will close the batch file. Here is what I have done so far:
#echo off
setlocal enableextensions enabledelayedexpansion
set RawData1=TempData%random%.tmp
set FileCtr=0
:MAIN
dir *.log /b | findstr /i /n ".log" > %RawData1%
for /f "tokens=1 delims=:" %%a in (%RawData1%) do set FileCtr=%%a
set /a ExitCode=%FileCtr% + 1
set UserChoice=%ExitCode%
echo.
echo +++++++++++++++++++++++++++
echo Weblog File Viewer
echo +++++++++++++++++++++++++++
for /f "tokens=1-2 delims=:." %%a in (%RawData1%) do echo %%a. %%b
echo %Exitcode%. To Quit.
set /p UserChoice= Choose item number from menu (%UserChoice%):
echo\
echo user entered: %UserChoice%
pause
:THEEND
del /q %RawData1%
So what this batch file can do for now is that it figures out the number of log files and makes a numbered menu from it. Of course it won't show the filetype which is how I wanted it. So "Kelley-Blue-Book.log" for example is shown only as "Kelley-Blue-Book". However, if the user selects say number 4 from the list the program will terminate because I couldn't figure out how to make it actually open the desired log file using notepad.
This should do what you want:
#echo Off
setlocal EnableDelayedExpansion
set "Count=0"
pushd "%~dp0"
echo.
echo +++++++++++++++++++++++++++
echo Weblog File Viewer
echo +++++++++++++++++++++++++++
for %%A in (*.log) do (
set /a "Count+=1"
set "Menu[!Count!]=%%~fA"
set "Number= !Count!"
echo !Number:~-3!. %%~nA
)
set /a "Count+=1"
set "Number= %Count%"
echo %Number:~-3%. To Quit.
:Prompt
set "UserChoice="
set /p "UserChoice= Choose item number from menu (%Count%):"
if not defined UserChoice goto Prompt
set "UserChoice=%UserChoice:"=%"
if "%UserChoice%"=="%Count%" goto Done
for /f "tokens=1,* delims==" %%A in ('set Menu') do (
if /i "Menu[%UserChoice%]"=="%%~A" (
notepad "%%~fB"
set "UserChoice="
)
)
if defined UserChoice echo Invalid Choice.
goto Prompt
:Done
popd
endlocal
exit /b 0
Let me know if you want any explanations.
#echo off
setlocal enableextensions
set RawData1=TempData%random%.tmp
rem Get numbered list of files
dir /b "*.log" | findstr /i /n ".log" > %RawData1%
rem We could use 0 as exitCode,
rem but to keep original behaviour
rem lets count the number of files
for /F "tokens=*" %%f in ('type %RawData1% ^| find /c /v "" ') do set /A ExitCode=%%f + 1
if %ExitCode%==0 (
echo No log files
goto endProcess
)
rem show menu
for /f "tokens=1-2 delims=:." %%a in (%RawData1%) do echo %%a. %%b
echo %Exitcode%. To Quit.
set UserChoice=%ExitCode%
set /p UserChoice= Choose item number from menu (%UserChoice%):
if "%UserChoice%"=="" goto :EOF
if "%UserChoice%"=="%ExitCode%" goto endProcess
rem Search indicated file in list
set SelectedFile=
for /f "tokens=2 delims=:" %%f in ('findstr /B "%UserChoice%:" %RawData1%') do set SelectedFile=%%f
if "%SelectedFile%"=="" (
echo Incorrect selection
goto endProcess
)
if not exist %SelectedFile% (
echo File deleted
goto endProcess
)
notepad %SelectedFile%
:endProcess
del /q %RawData1%