I haven't worked with batch files before but I would like to create a batch file that runs a command line program which will output one of two lines depending on success or failure. Is there any way I can capture the executable's output without writing it to a temporary file?
Thanks in advance
put the program in a for /f loop (example):
for /f "delims=" %%a in ('myProgram.exe -a -b -c') do if /i "%%~a"=="failure" (call:dothis) else call:success
if %errorlevel%==0 call:success
if %errorlevel%==1 call:dothis
goto:eof
:dothis
echo Error found.
exit /b 1
:success
echo No error found.
exit /b 0
Related
I am trying to build a batch file that pings multiple devices on our network and continues logging ping results data in an output file in an infinite loop. However, the infinite loop gets hung up because the output file is open. Once I manually close the output file, the loop begins another iteration and logs more data. How do I automate this step? I've gone through so many options with taskkill, but none of them will close the output file for some reason. Other Notepad files close, but not the output file running on notepad.
Thanks for you help! Code is below:
#echo off
if exist C:\Users\Tsgadmin\Desktop\data\computers.txt goto Label1
echo.
echo Cannot find C:\Users\Tsgadmin\Desktop\data\computers.txt
echo.
Pause
goto :eof
:Label1
:loop
echo ================================================= >> C:\Users\Tsgadmin\Desktop\ping_firepanels_output.txt
echo PingTest executed on %date% at %time% >> C:\Users\Tsgadmin\Desktop\ping_firepanels_output.txt
for /f %%i in (C:\Users\Tsgadmin\Desktop\data\computers.txt) do call :Sub %%i
notepad C:\Users\Tsgadmin\Desktop\ping_firepanels_output.txt
choice /n/t:c,<10>/c:cc
echo ================================================= >> C:\Users\Tsgadmin\Desktop\ping_firepanels_output.txt
echo. >> C:\Users\Tsgadmin\Desktop\ping_firepanels_output.txt
start notepad.exe
for /f "tokens=2" %%x in ('tasklist ^| findstr notepad.exe') do set PIDTOKILL=%%x
taskkill /F /IM notepad.exe > nul
goto loop
goto :eof
:Sub
echo Testing %1
ping -n 1 %1 >> C:\Users\Tsgadmin\Desktop\ping_firepanels_output.txt | find /i "(0% loss)"
echo %1 Testing done
echo %1 Testing done >> C:\Users\Tsgadmin\Desktop\ping_firepanels_output.txt
Here is your batch code rewritten for this task:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "LogFile=%USERPROFILE%\Desktop\ping_firepanels_output.txt"
set "ListFile=%USERPROFILE%\Desktop\data\computers.txt"
if exist "%ListFile%" goto PrepareForPings
echo/
echo Cannot find file: "%ListFile%"
echo/
endlocal
pause
goto :EOF
rem Delete existing log file before running the echo requests.
rem Get just file name with file extension without path from
rem log file name with path specified at top of the batch file.
:PrepareForPings
del "%LogFile%" 2>nul
for /F %%I in ("%LogFile%") do set "LogFileName=%%~nxI"
rem Always terminate (not kill) running Notepad instance with having
rem the log file opened for viewing before running first/next test run.
:PingLoop
%SystemRoot%\System32\taskkill.exe /FI "WINDOWTITLE eq %LogFileName% - Notepad" >nul 2>nul
echo =================================================>>"%LogFile%"
>>"%LogFile%" echo PingTest executed on %DATE% at %TIME%
echo/>>"%LogFile%"
for /F "usebackq" %%I in ("%ListFile%") do (
echo Testing %%I ...
%SystemRoot%\System32\ping.exe -n 1 -w 500 %%I>nul
if errorlevel 1 (
echo %%I is not available in network (no reply^).>>"%LogFile%"
) else echo %%I is available.>>"%LogFile%"
echo %%I testing done.
)
echo =================================================>>"%LogFile%"
echo/>>"%LogFile%"
start "" %SystemRoot%\notepad.exe "%LogFile%"
echo/
%SystemRoot%\System32\choice.exe /C NY /N /T 10 /D Y /M "Run again (Y/n): "
echo/
if errorlevel 2 goto PingLoop
endlocal
In general it is advisable to define environment variables with names of files specified multiple times in the batch file at top to make it easier to modify them in future.
On referencing those file environment variables it is strongly recommended to enclose the name in double quotes to get a working batch file also when file name with path contains a space character or one of these characters: &()[]{}^=;!'+,`~
If a file name enclosed in double quotes is specified as text file of which lines to read in a for /F command line, it is necessary to use option usebackq to get interpreted the file name enclosed in double quotes as file name and not as string to process by FOR.
The DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/ explains why it is better to use echo/ instead of echo. to output an empty line.
The TASKKILL command used to send Notepad the terminate signal for a graceful termination should be send only to the Notepad instance having the log file opened and not any other perhaps running Notepad instance.
An ECHO line redirected to a file with > or >> with a space left to redirection operator results in having this space also written as trailing space into the file. For that reason there should be no space between text to write into the file and redirection operator. A space right to > or >> would be no problem as not written into the file.
When a variable text is output on an ECHO line redirected into a file which could end with 1, 2, 3, ... 9, it is necessary to specify the redirection from STDOUT into the file with >> at beginning of the line as otherwise 1>>, 2>>, ... would be interpreted different as expected on execution of the ECHO command line. Read also the Microsoft article about Using Command Redirection Operators.
There is no subroutine necessary for this task. A command block starting with opening parenthesis ( and matching ) can be used here too. That makes the execution of the loop a bit faster, not really noticeable faster, but nevertheless faster.
There is a text written with echo into the log file containing also a closing parenthesis ) not within a double quoted string. This ) would be interpreted as matching ) for opening ( of true branch of IF condition. It is necessary to escape ) with caret character ^ to get ) interpreted as literal character by Windows command interpreter.
PING exits with exit code 1 if the echo request was not replied. Otherwise on successful reply the exit code is 0. It is better to evaluate the exit code via errorlevel than filtering the language dependent output.
New instance of Notepad with the log file to view is started by this batch file using command start to run Notepad in a separate process running parallel to command process executing the batch file. Otherwise the execution of the batch file would be halted as long as the started Notepad instance is not closed by the user. That different behavior can be easily seen on removing start "" at beginning of the command line starting Notepad.
The command CHOICE gives the user of the batch file the possibility to exit the loop by pressing key N (case-insensitive) within 10 seconds. Otherwise the user prompt is automatically answered with choice Y and the loop is executed once again by first terminating running Notepad.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
choice /?
del /?
echo /?
endlocal /?
for /?
goto /?
if /?
pause /?
ping /?
set /?
setlocal /?
start /?
taskkill /?
See also Windows Environment Variables for details on environment variables USERPROFILE and SystemRoot as used in this batch file.
I have a batch file that will run several other file (lets call it procedure file) such as .bat,.exe,.py, etc...
if Not Exist JobStreamUnitTest_CreateTextPython_4-27-2015.txt (
Start /wait /b C:\Users\blee2\Documents\UnitTest\CreateTextFile.py || exit %errorlevel%
copy /y nul JobStreamUnitTest_CreateTextPython_4-27-2015.txt
)
if Not Exist JobStreamUnitTest_CreateTextBatch_4-27-2015.txt (
Start /wait /b C:\Users\blee2\Documents\UnitTest\CreateNewFile.bat || exit %errorlevel%
copy /y nul JobStreamUnitTest_CreateTextBatch_4-27-2015.txt
)
if Not Exist JobStreamUnitTest_CreateTextConsole_4-27-2015.txt (
Start /wait /b C:\Users\blee2\Documents\UnitTest\TestConsole.exe apple || exit %errorlevel%
copy /y nul JobStreamUnitTest_CreateTextConsole_4-27-2015.txt
)
if Not Exist JobStreamUnitTest_HelloWorld_4-27-2015.txt (
Start /wait /b C:\Users\blee2\Documents\UnitTest\HelloWorld.bat || exit %errorlevel%
copy /y nul JobStreamUnitTest_HelloWorld_4-27-2015.txt
)
So basically, the batch file will check if the following file need to be run based on the existence of dummy file associate with each of the procedure file.
This will prevent us from running successfully run if we are to run the batch file the second time.
If there is no error in any of the procedure file then the code will work fine.
The exit error will only work if the file/filepath is incorrect.
The problem I am facing is that, since the Start /wait /b will always execute regardless of if one of my procedure file have an error. Therefore the exit %errorlevel% would not be run.
How do I allow the batch file to detect an error if a procedure file is broken?
I would like to exit/terminal the batch file if one of the procedure file is not working. Any thoughts?
PS. /wait is needed because the start should be running in a sequential order.
/b is needed or else the program will stop after running a .bat ; /b allow us to run the batch file in the same cmd window.
Appreciate any help and thank you
Edited:
The code would work if i do the following. But I am hoping to have a consistency format in my batch file, since the batch file is being generated by C# with parsing of .xml files.
if Not Exist JobStreamUnitTest_CreateTextPython_4-27-2015.txt (
C:\Users\blee2\Documents\UnitTest\CreateTextFile.py || exit %errorlevel%
copy /y nul JobStreamUnitTest_CreateTextPython_4-27-2015.txt
)
if Not Exist JobStreamUnitTest_CreateTextBatch_4-27-2015.txt (
Start /wait /b C:\Users\blee2\Documents\UnitTest\CreateNewFile.bat || exit %errorlevel%
copy /y nul JobStreamUnitTest_CreateTextBatch_4-27-2015.txt
)
I have found some issues in start /WAIT /B any_program || exit %errorlevel%:
#1 - %errorlevel% variable will be expanded at parse time. Thus your script never returns proper exit code. See EnableDelayedExpansion.
#2 - || conditional command execution: unfortunately I can't document it properly, but all my attempts with it failed in relation to start command...
IMHO next code snippet (the only example) could work as expected:
if Not Exist JobStreamUnitTest_CreateTextBatch_4-27-2015.txt (
start /B /WAIT C:\Users\blee2\Documents\UnitTest\CreateNewFile.bat
SETLOCAL enabledelayedexpansion
if !errorlevel! NEQ 0 exit !errorlevel!
ENDLOCAL
copy /y nul JobStreamUnitTest_CreateTextBatch_4-27-2015.txt
)
#3 - a bug in the implementation of the start command.
start /WAIT /B doesn't work (the /wait argument is ignored):
==>start /WAIT /B wmic OS GET Caption & echo xxx
xxx
==>Caption
Microsoft Windows 8.1
There's a simple workaround (from SupeUser) as start /B /WAIT works:
==>start /B /WAIT wmic OS GET Caption & echo xxx
Caption
Microsoft Windows 8.1
xxx
I'm running a command in a batch file[Just for info: this command runs a python script which generates different outputs]
The code is as follows:
:meshfunc
echo "starting command"
echo "!inst_dir!runME.bat -parameter1 !parameter2! !parameter1v! -script pythonscript.py"
echo start_time=!time!
for /F "delims=" %%i IN ('"!inst_dir!runME.bat -parameter1 !parameter2! !parameter1v! -script pythonscript.py"') DO (
set cmdline=%%i
echo currentENDline=!cmdline!
)
EXIT /B 0
The output of the script is:
PS: I have stripped the output lines for obvious reasons, but they shouldn't matter here
So my questions is :
If i run the same command without a for loop , it will complete in maybe 30 sec without the warning at the end.
However, if I run it inside a for loop, it takes much longer about 3 mins and gives the warning at the end
Why am I'm getting the Warning at the end as shown. Why is this happening?
Because for /F execute the command enclosed in parentheses and store all its output in a temporary disk file until the command ends; after that, it start to repeatedly execute the group of commands. In this way, if the output is very large, the temporary file needs to grow several times and such a process takes some time... It should be faster to redirect the output to a disk file and then process such a file with for /F:
:meshfunc
echo "starting command"
echo "!inst_dir!runME.bat -parameter1 !parameter2! !parameter1v! -script pythonscript.py"
echo start_time=!time!
call "!inst_dir!runME.bat" -parameter1 !parameter2! !parameter1v! -script pythonscript.py > output.txt
for /F "delims=" %%i IN (output.txt) DO (
set cmdline=%%i
echo currentENDline=!cmdline!
)
EXIT /B 0
I have a batch file that I am trying to get working and I'm having trouble suppressing the output of a couple of commands. One solution I've tried is to start the commands with the # symbol - (something I've done sucessfully plenty of times). Here is the code:
#echo off
setlocal
for /f "tokens=*" %%i in (tmp\hdata.txt) do (
::' just a note - hdata.txt contains lines of text such as,
::' for example:
::' jquery_javascript_32
::' underscore_javascript_9
::' I couldn't do this with simple delimiters because some lines are like:
::' underscore_js_javascript_43
set "id=%%i"
set filewithnum=!id:_javascript_=!
::' *** BELOW throws error ***
#echo !filewithnum!|findstr /R "[0-9]$" && set "file=!filewithnum:~,-1!" >nul 2>&1
::' *** BELOW throws error ***
#echo !filewithnum!|findstr /R "[0-9]$" && set "file=!file:~,-1!" >nul 2>&1
echo !file!
)
endlocal
exit /b
The lines commented above throw: '#echo' is not recognized as an internal or external command, operable program or batch file.
Seems weird.
Any ideas as to what's happening here?
Note: The extra ' after the comment :: above is to make syntax highlighting work properly on stackoverflow.
Once you've fixed the points Magoo raised in the comments, you need to suppress the output of findstr. You don't need # since command echo mode is already turned off at the start of the script.
You've got this:
#echo !filewithnum!|findstr /R "[0-9]$" && set "file=!filewithnum:~,-1!" >nul 2>&1
So you are redirecting the output of the set command! To redirect the output of findstr, do this:
echo !filewithnum!|findstr /R "[0-9]$" >nul 2>&1 && set "file=!filewithnum:~,-1!"
I have a bat file that I created, it adds keys to the windows registry and then calls another bat file, QGIS.bat (this bat file starts an application called QGIS).
It works most of the time but every now and then, when it calls QGIS.bat nothing happens, the command window stays open but QGIS (started by the QGIS.bat file) will not start.
In the command window(cmd) all it says is call .\usbgis\apps\qgis\bin\qgis.bat
(Just a note QGIS is a portable application that runs from a USB memory stick, might that be part of the problem?)
So my question. Is there a way you can terminate a bat file if it douse not close in 3 min or if the other bat file douse not start?
Thanks,
This is what I'm talking about in my comment:
#echo off
setlocal enabledelayedexpansion
set sPath=C:\Program Files\Internet Explorer
set sprog=iexplore.exe
set inc=0
:loop
if exist "%sPath%\%sProg%" (echo %sProg%) else exit /b
set /a inc+=1
if "!inc!" equ "30" (Echo Exiting & exit /b)
for /f %%a in (
'tasklist /NH /FI "Imagename eq %sProg%"^|findstr /i "INFO:"') do (
if not errorlevel 1 (
ping -n 11 127.0.0.1>nul
goto :loop
)
)
Obviously change the path and file to match yours. I just needed something for testing here.