As I am new here, I have some problems "coding" in batch file.
I have an input-output file file.txt with some data (Name Surname Sex Age) and also have some functions that should be made with this file, e.g.:
add a person,
delete a person,
sort people,
exit,
show the list
The main problem happens when I choose the function to delete a person. I have tried to overwrite the file with type %~f1 | findstr /v %name% > %~f1, but it deletes everything from the input-output file. I have also tried type %~f1 | findstr /v %name% >> %~f1, but it adds some lines that I do not need...
I need a function that would delete the whole line, which contains the entered name (or surname) and would show me the output file without that line.
#echo off
:PAT
cls
color 4f
echo.
if exist %~f1 (
rem goto PRA
) else (
echo ERROR
goto END
)
:PRA
echo Menu:
echo 1) Add a person
echo 2) Delete a person
echo 3) Sort
echo 4) Exit
echo 5) Show the list
echo.
choice /c 12345 /m "Choice: "
if errorlevel 5 goto AAA
if errorlevel 4 goto END
if errorlevel 3 goto SOR
if errorlevel 2 goto DEL
if errorlevel 1 goto ADD
:EOF
pause
:END
choice /m "Continue?"
if errorlevel 2 goto NE
if errorlevel 1 goto TAI
:TAI
cls
goto PAT
:NE
Exit
:SOR
echo Which sort?
echo 1: A-Z
echo 2: Z-A
choice /c 12 /m "Choice: "
if errorlevel 2 goto ZTA
if errorlevel 1 goto ATZ
:ATZ
type %~f1 | sort /+1 /o %~f1
cls
goto PRA
:ZTA
type %~f1 | sort /+1 /r /o %~f1
cls
goto PRA
:DEL
echo Enter the name:
set /p name=
type %~f1 | findstr /v /i %name% > %~f1
goto PRA
:ADD
set /p name=Enter the name:
set /p surname=Enter the surname:
set /p sex=Enter the sex:
set /p age=Enter the age:
echo %vardas% %surname% %sex% %age%>>%~f1
echo.
cls
goto PRA
:AAA
cls
echo _________________________
more %~f1
echo _________________________
goto PRA
I have a batch file I am working on trying to use to achieve up IIS server logs. Here is the details of all files involved and the final output I am seeing
Batch file:
setlocal
set zipfolder=D:\Statscheck\zipped\
set statsdir=D:\Statscheck\
set statsfolder=Statscheck
d:
cd\
cd\%statsfolder%
dir w3* /s /b > d:\server-scripts\temp\process.txt
set THECSVFILE=d:\server-scripts\temp\process.txt
::read %THECSVFILE% and loop through each line
for /F "usebackq tokens=* delims=\" %%A in (%THECSVFILE%) do (
set dirname=%%A
)
for /F "usebackq tokens=3 delims=\" %%A in (%THECSVFILE%) do (
set filename=%%A
call :process_line
)
:process_line
set buildfile= %zipfolder%stats-%filename%-archive.zip
echo filename %buildfile% >>D:\server-scripts\temp\output.txt
echo directory %dirname% >>D:\server-scripts\temp\output.txt
Process.txt:
D:\Statscheck\dphs92\W3SVC1532191319
D:\Statscheck\kcnw\W3SVC232480661
D:\Statscheck\master\W3SVC84257322
D:\Statscheck\warlords\W3SVC1913965975
output.txt:
filename D:\Statscheck\zipped\stats-dphs92-archive.zip
directory D:\Statscheck\warlords\W3SVC1913965975
filename D:\Statscheck\zipped\stats-kcnw-archive.zip
directory D:\Statscheck\warlords\W3SVC1913965975
filename D:\Statscheck\zipped\stats-master-archive.zip
directory D:\Statscheck\warlords\W3SVC1913965975
filename D:\Statscheck\zipped\stats-warlords-archive.zip
directory D:\Statscheck\warlords\W3SVC1913965975
As you can see from the output it is building the filename option correctly however the directory that is being pulled is the last one in the list. Is it not looping.
Extensive searches found no solution in batch to parse netstat -bano (same switch as -nab, -bna, -anb, -nba, nabo, etc.) so all info from a given network connection is on the same line.
Netstat's -ban switches are used to:
-b = display executable
-a = display all connections and listening ports
-n = display addresses and ports in numerical form.
-o = display owning process ID for each connection (i.e., PID)
But netstat adds the file name to the next line, making processing the output very difficult. Extensive searches didn't find any answers in batch.
I created a way to parse it by looking for a ] (right bracket) as the last character on a line. If it is a ], then basically output the "combined" line, which now contains the executable.
My code is posted as an answer, but does an ugly job since it has to use files to handle the parsing instead of variables.
The previous version of this script was missing a backslash. Additionally the script would delete the output file. Creating the file as %computername%--NETSTAT.txt instead of NETSTAT--%computername%.txt fixes the problem.
#ECHO OFF
SetLocal
REM Method of finding last character-of-a-string-from-a-variable
REM http://stackoverflow.com/a/15662607/1569434
REM Get the script's path so all needed files can sit in the same folder
SET SCRIPTPATH=%~p0
CD %SCRIPTPATH%
REM Read and pass each line in file one at a time to sub 'FindEXE'
SET CONCATLINE=
SET HEADERROW=
SET /A LINECOUNT = 0
#echo LINECOUNT = %LINECOUNT%
del %SCRIPTPATH%\netstat*.txt /q 2>nul
netstat -bano>%SCRIPTPATH%\netstat0.txt
REM Copy all lines except those with "TIME_WAIT" into text file
FINDSTR /V /I /C:"TIME_WAIT" %SCRIPTPATH%\netstat0.txt>%SCRIPTPATH%\netstat1.txt
REM Delete first two lines, which are a header and a blank line
for /f "skip=2 delims=*" %%a in (%SCRIPTPATH%\netstat1.txt) do (echo %%a>>%SCRIPTPATH%\netstat2.txt)
REM Search for and process file based on matching text
REM This sub begins putting each netstat connection on one line
for /f "delims=*" %%A in (%SCRIPTPATH%\netstat2.txt) do call :FindTXT1 %%A
REM netstat3 will have all data from given connection on one line
SET /A LINECOUNT = 0
for /f "delims=*" %%A in (%SCRIPTPATH%\netstat3.txt) do call :FindTXT2 %%A
REM Keep only header and unique (i.e., those with "[::]") 'listening' connections
FINDSTR /I /C:"LISTENING" /C:"Local Address" %SCRIPTPATH%\netstat4.txt>%SCRIPTPATH%\netstat5.txt
FINDSTR /I /C:"[::]:" /C:"Local Address" %SCRIPTPATH%\netstat5.txt>%SCRIPTPATH%\netstat6.txt
MOVE /Y %SCRIPTPATH%\netstat6.txt %SCRIPTPATH%\%computername%--NETSTAT.txt
del %SCRIPTPATH%\netstat*.txt /q 2>nul
#echo off
echo done.
EndLocal
goto :EOF
:FindTXT1
REM We've got a line sent to us. Set variable to entire line using * (instead of %1)
SET CURRENTLINE=%*
SET /A LINECOUNT = %LINECOUNT% + 1
REM Add line feed after header row and return to main script
IF "%LINECOUNT%" == "1" (
SET HEADERROW=%CURRENTLINE%
#ECHO %CURRENTLINE%> %SCRIPTPATH%\netstat3.txt
goto :eof
)
REM Append a comma and CURRENTLINE to CONCATLINE. NOTE: Script expecting comma; don't use semi-colon
SET CONCATLINE=%CONCATLINE%,%CURRENTLINE%
REM When echo line, remove first char (comma, inserted above) using:
REM http://ss64.com/nt/syntax-substring.html
REM If last char is "]" then print, otherwise append
IF "%CURRENTLINE:~-1%"=="]" (
REM #echo right bracket=FOUND
#echo %CONCATLINE:~1%>>%SCRIPTPATH%\netstat3.txt
SET CONCATLINE=
) else (
REM #echo right bracket=NOT found
)
REM If line = "Can not obtain ownership information" then print, otherwise append
IF "%CURRENTLINE%"=="Can not obtain ownership information" (
REM #echo No Ownership=TRUE
#echo %CONCATLINE:~1%>>%SCRIPTPATH%\netstat3.txt
SET CONCATLINE=
)
goto :eof
:FindTXT2
REM We've got a line sent to us. Set variable to entire line using * (instead of %1)
SET CURRENTLINE=%*
SET /A LINECOUNT = %LINECOUNT% + 1
REM Add line feed after header row and return to main script
IF "%LINECOUNT%" == "1" (
SET HEADERROW=%CURRENTLINE%
#ECHO %CURRENTLINE%> %SCRIPTPATH%\netstat4.txt
goto :eof
)
REM If last char is "]" then search, otherwise append.
REM Without "DelayedExp...", variable sets to value from previous FOR loop
IF "%CURRENTLINE:~-1%"=="]" (
SetLocal ENABLEDELAYEDEXPANSION
REM IP6 EXEs result in 3 sets of [], so find and set var to last one, which is where EXE lives
FOR /f "tokens=1,2,3,4,5,6 delims=[]" %%a in ("%CURRENTLINE%") do (
SET BINNAME1=%%b
SET BINNAME2=%%f
IF "!BINNAME1!" == "::" (
REM #ECHO BINNAME1=!BINNAME1!>>%SCRIPTPATH%\netstat4.txt
SET BINNAME=!BINNAME2!
REM #echo %CURRENTLINE%;BINNAME=!BINNAME2!>>%SCRIPTPATH%\netstat4.txt
) else (
SET BINNAME=!BINNAME1!
REM #echo %CURRENTLINE%;BINNAME=!BINNAME1!>>%SCRIPTPATH%\netstat4.txt
)
#echo %CURRENTLINE%;BINNAME=!BINNAME!>>%SCRIPTPATH%\netstat4.txt
)
) else (
#echo %CURRENTLINE%>>%SCRIPTPATH%\netstat4.txt
SetLocal DISABLEDELAYEDEXPANSION
)
goto :eof
Created solution in batch to concatenate all output for a given connection so it's on one line. Save script (below) as a batch file and when run it will create a file called "NETSTAT--%computername%.txt" in the same folder as the script, where %computername% will be replaced with the hostname of computer it's run on.
#ECHO OFF
SetLocal
REM Method of finding last character-of-a-string-from-a-variable
REM http://stackoverflow.com/a/15662607/1569434
REM Get the script's path so all needed files can sit in the same folder
SET SCRIPTPATH=%~p0
CD %SCRIPTPATH%
REM Read and pass each line in file one at a time to sub 'FindEXE'
SET CONCATLINE=
SET HEADERROW=
SET /A LINECOUNT = 0
#echo LINECOUNT = %LINECOUNT%
del %SCRIPTPATH%\netstat*.txt /q 2>nul
netstat -bano>%SCRIPTPATH%\netstat0.txt
REM Copy all lines except those with "TIME_WAIT" into text file
FINDSTR /V /I /C:"TIME_WAIT" %SCRIPTPATH%\netstat0.txt>%SCRIPTPATH%\netstat1.txt
REM Delete first two lines, which are a header and a blank line
for /f "skip=2 delims=*" %%a in (%SCRIPTPATH%\netstat1.txt) do (echo %%a>>%SCRIPTPATH%\netstat2.txt)
REM Search for and process file based on matching text
REM This sub begins putting each netstat connection on one line
for /f "delims=*" %%A in (%SCRIPTPATH%\netstat2.txt) do call :FindTXT1 %%A
REM netstat3 will have all data from given connection on one line
SET /A LINECOUNT = 0
for /f "delims=*" %%A in (%SCRIPTPATH%\netstat3.txt) do call :FindTXT2 %%A
REM Keep only header and unique (i.e., those with "[::]") 'listening' connections
FINDSTR /I /C:"LISTENING" /C:"Local Address" %SCRIPTPATH%\netstat4.TXT>%SCRIPTPATH%\netstat5.TXT
FINDSTR /I /C:"[::]:" /C:"Local Address" %SCRIPTPATH%\netstat5.TXT>%SCRIPTPATH%\netstat6.TXT
MOVE /Y %SCRIPTPATH%\netstat6.txt %SCRIPTPATH%\NETSTAT--%computername%.txt
del %SCRIPTPATH%netstat*.txt /q 2>nul
#echo off
echo done.
EndLocal
goto :EOF
:FindTXT1
REM We've got a line sent to us. Set variable to entire line using * (instead of %1)
SET CURRENTLINE=%*
SET /A LINECOUNT = %LINECOUNT% + 1
REM Add line feed after header row and return to main script
IF "%LINECOUNT%" == "1" (
SET HEADERROW=%CURRENTLINE%
#ECHO %CURRENTLINE%> %SCRIPTPATH%\netstat3.txt
goto :eof
)
REM Append a comma and CURRENTLINE to CONCATLINE. NOTE: Script expecting comma; don't use semi-colon
SET CONCATLINE=%CONCATLINE%,%CURRENTLINE%
REM When echo line, remove first char (comma, inserted above) using:
REM http://ss64.com/nt/syntax-substring.html
REM If last char is "]" then print, otherwise append
IF "%CURRENTLINE:~-1%"=="]" (
REM #echo right bracket=FOUND
#echo %CONCATLINE:~1%>>%SCRIPTPATH%\netstat3.txt
SET CONCATLINE=
) else (
REM #echo right bracket=NOT found
)
REM If line = "Can not obtain ownership information" then print, otherwise append
IF "%CURRENTLINE%"=="Can not obtain ownership information" (
REM #echo No Ownership=TRUE
#echo %CONCATLINE:~1%>>%SCRIPTPATH%\netstat3.txt
SET CONCATLINE=
)
goto :eof
:FindTXT2
REM We've got a line sent to us. Set variable to entire line using * (instead of %1)
SET CURRENTLINE=%*
SET /A LINECOUNT = %LINECOUNT% + 1
REM Add line feed after header row and return to main script
IF "%LINECOUNT%" == "1" (
SET HEADERROW=%CURRENTLINE%
#ECHO %CURRENTLINE%> %SCRIPTPATH%\netstat4.txt
goto :eof
)
REM If last char is "]" then search, otherwise append.
REM Without "DelayedExp...", variable sets to value from previous FOR loop
IF "%CURRENTLINE:~-1%"=="]" (
SetLocal ENABLEDELAYEDEXPANSION
REM IP6 EXEs result in 3 sets of [], so find and set var to last one, which is where EXE lives
FOR /f "tokens=1,2,3,4,5,6 delims=[]" %%a in ("%CURRENTLINE%") do (
SET BINNAME1=%%b
SET BINNAME2=%%f
IF "!BINNAME1!" == "::" (
REM #ECHO BINNAME1=!BINNAME1!>>%SCRIPTPATH%\netstat4.txt
SET BINNAME=!BINNAME2!
REM #echo %CURRENTLINE%;BINNAME=!BINNAME2!>>%SCRIPTPATH%\netstat4.txt
) else (
SET BINNAME=!BINNAME1!
REM #echo %CURRENTLINE%;BINNAME=!BINNAME1!>>%SCRIPTPATH%\netstat4.txt
)
#echo %CURRENTLINE%;BINNAME=!BINNAME!>>%SCRIPTPATH%\netstat4.txt
)
) else (
#echo %CURRENTLINE%>>%SCRIPTPATH%\netstat4.txt
SetLocal DISABLEDELAYEDEXPANSION
)
goto :eof
Im attempting to get a block of text from a file I have already created and store that information into a new file. The text file id like to parse is set up like this:
HostName: xxxxxx
(8 or so lines of information)
HostName: xxxxxx
The largest problem I am having is that between the blocks of text I am specifically looking for the word "admin". I am able to find and return the line with the word admin in it, now I need to write a loop to grab the information above and below if the word admin is found within that block of text (I was going to use an empty line as the delimiter as thats consistent throughout my file).
Ive written a few for loops but none of them have given me what id like. Any help would be appreciated.
Thanks
The program below do what you want:
#echo off
setlocal EnableDelayedExpansion
rem Create the info removing empty lines
(for /F "delims=" %%a in ('schtasks /query /fo list /v') do echo %%a) > schtasks.txt
rem Add an additional "HostName:" line at end as delimiter
echo HostName: >> schtasks.txt
rem Create a vector of number of lines containing "HostName:"
set i=0
for /F "delims=:" %%a in ('findstr /N "HostName:" schtasks.txt') do (
set /A i+=1
set header[!i!]=%%a
)
rem Seek for the LINES containing "admin"
for /F "delims=:" %%a in ('findstr /N /I "administrator" schtasks.txt') do (
rem Seek for the NEXT section that contains "admin" line
for /L %%i in (1,1,%i%) do if %%a gtr !header[%%i]! set thisSection=%%i
rem Locate that section
set /A start=header[!thisSection!], nextSection=thisSection+1
set /A end=header[!nextSection!]-1
rem ... and show it
set line=0
for /F "delims=" %%a in (schtasks.txt) do (
set /A line+=1
if !line! geq !start! if !line! leq !end! echo %%a
)
echo ----------------------------------------------
)
del schtasks.txt
PS - Of course that MS-DOS/Windows Batch is a programming language!
Drag and drop .bat, it takes the files,
puts it in 2 lists and process both list simultanously.
I passed a path : X:\folder\folder number\begin.txt into %1
it's working fine if i have foldernumber
PUSHD %~dp0
:loop
IF ["%~f1"] EQU [""] goto :out
echo %~f1>>list
set /a count+=1
SHIFT
goto :loop
POPD
:out
if %count% LEQ 1 (copy list list1 && goto :START)
set /a count2=%count%/2
more /e +%count2% list > list2
set count=0
setlocal enabledelayedexpansion
for /F "eol=; tokens=* delims=," %%i in (list) do (
set /a count+=1
if !count! leq !count2! echo %%i >>list1
)
endlocal
:: Create the 2nd .bat for multiprocessing and start multiprocessing
more /e +88 mybat.bat > temp.bat
START "2nd Process mybat2" temp.bat
:start
for /f "eol=; tokens=* delims==," %%i in (list1) do call :SEARCH %%i
goto :END
:: 88th line here
for /f "eol=; tokens=* delims==," %%k in (list2) do call :SEARCH %%k
goto :END
:search
setlocal enabledelayedexpansion
for %%A in (jan feb mar apr mai etc...) DO (
findstr /m "%%A" "%~f1" > NUL
if !ERRORLEVEL! == 0 (
call :theend %~1 %%A
goto :EOF
)
)
endlocal
I get this error message "FINDSTR: Cannot open X:\folder\folder number\begin.txt"
Is there a way to fix this findstr problem?
thanks
To let us see if your file dropping is OK:
Can you create a batch file with these contents
echo %*
set /p dummy=press return
drop a file, with spaces in the name, onto it and post the results?