Batch File arbitrary command-line arguments - batch-file

I want the program to process an arbitrary number of command-line arguments, but I'm unsure how to implement a for loop to go through multiple shift commands. Also, the program shouldn't close the command prompt window when it ends.
Here is what I have so far:
#echo off
if "%1"=="" goto skip
if "%1"=="-ti" time /t
if "%1"=="-da" date /t
if "%1"=="-c" cls
if "%1"=="-ip" ipconfig
if "%1"=="-d" dir
if "%1"=="-p" path
if "%1"=="-v" ver
if "%1"=="-t" type
if "%1"=="-m" md
exit /b
:skip
echo No arguments!
I'd like to have the following command-line arguments run properly:
C:\>batchfile –d –ti –da –ip –v
C:\>batchfile
C:\>batchfile –d –m CSC3323 –d
C:\>batchfile –d –t batchfile.bat –m CSC3323 –d

Use this code to loop through your arguments in a file called batchfile.bat:
#echo off
echo arguments: "%*"
:loop
if "%~1"=="" goto skip
if "%~1"=="-ti" time /t
if "%~1"=="-da" date /t
if "%~1"=="-c" cls
if "%~1"=="-ip" ipconfig
if "%~1"=="-d" dir
if "%~1"=="-p" path
if "%~1"=="-v" ver
if "%~1"=="-t" type
if "%~1"=="-m" md
shift
goto loop
:skip
echo No arguments!
pause
and call the batchscript like this:
start batchfile.bat -ti -d -ti -da -ip -v
start batchfile.bat
start batchfile.bat -d -m CSC3323 -d
start batchfile.bat -d -t batchfile.bat -m CSC3323 -d

Related

Goto not working properly in batch script

Given the following:
#ECHO OFF
SetLocal EnableDelayedExpansion
cls
adb shell am start -a android.intent.action.MAIN -n com.krohne.OpticheckMobile/Droid.MainActivity -e run_bb_tests true
adb logcat -c
set condition=false
goto while
:end
echo macac
exit 0
:while
adb logcat -d -v raw | find "BBTests" | FOR /f "delims=" %%a in ('more') do (
#echo Line is %%a
if %%a==BBTestsCompleted (
echo Condition met. Exiting now ..
goto :end
)
)
goto :while
The script is not exiting through :end label, but it loops the while condition forever (the if statement is met)
The command line under :while:
adb logcat -d -v raw | find "BBTests" | FOR /f "delims=" %%a in ('more') do (
contains pipes (|), each of which initiates a new Command Prompt (cmd) instance for either side, so the for /F loop in the pipe is not executed in the hosting cmd.exe instance where the batch script runs in. Therefore, it cannot find the label :end. Furthermore, there are two contexts in which cmd.exe can run: Command Prompt context and batch file context; the instances created by a pipe are running in Command Prompt context where labels cannot be used as their usage is limited to batch file context and goto just has no effect.
For your code to work you must move the for /F loop into the hosting cmd.exe instance. This can be achieved by moving the pipes into the command line that is executed by the for /F loop (note that they need to be escaped like ^| to become hidden from the hosting cmd.exe instance):
for /F "delims=" %%a in ('adb logcat -d -v raw ^| find "BBTests" ^| more') do (
In the while class adb command contains pipes which mean that if one command failed execute other if that also fails execute other and that's the reason behind that you are not getting desired output, for this execute every adb command individually in :while class rather that using pipes

How to capture returned errorlevel of a sub-batch file and proceed accordingly

I am working on a batch file that calls 4 other batch files. If the sub-batch file returns with an errorlevel code other than 0, I want the parent batch file to capture it, send out an email and exit the parent batch file. However, as soon as the first child batch file is called and returns with a non-zero errorlevel, none of the subsequent commands in the parent batch file run. Here is my batch code:
rem ** setup so it logs itself **
set parent=%~dp0
set me=%~n0
set LOGFILE=%parent%logs\%me%.log 2>&1
if exist "%LOGFILE%" del %LOGFILE% /f /s /q
call :LOG > %LOGFILE%
exit
:LOG
#ECHO OFF
SETLOCAL ENABLEEXTENSIONS EnableDelayedExpansion
echo ParentDir: %parent%
echo ProgramName: %me%
echo.
rem ** script variables **
set batFile1=%parent%FILE1.bat
set batFile2=%parent%FILE2.bat
set batFile3=%parent%FILE3.bat
set batFile4=%parent%FILE4.bat
set FromEmail=server#domain.com
set Recipient=adminuser#domain.com
set CCRecipient=
set Subject=Email Subject
set Message=There was an error in running nightly batch files. Please look at the logs to determine which batch file is causing a problem. \n\nAt your service\nAdmin
set Server=smtp.domain.com
set Port=25
rem ** run bat files and capture error message **
echo.
echo Start: Send Email
set Message=Debug test code
c:\APPS\sendemail.exe -f %FromEmail% -t %Recipient% -cc %CCRecipient% -u "%Subject%" -m "%Message%" -v -s %Server%
call %batFile1%
set exitcode=%ERRORLEVEL%
echo %exitcode%
echo.
echo Start: Send Email
set Message=Debug test code !exitcode!
c:\APPS\sendemail.exe -f %FromEmail% -t %Recipient% -cc %CCRecipient% -u "%Subject%" -m "%Message%" -v -s %Server%
if %exitcode% NEQ 0 (
echo.
set Message=Execution of !batFile1! failed with error message !errorcode!. Examine the logs and fix any issues before next run.\n\nAt your service\nAdmin
echo Start: Send Email
c:\APPS\sendemail.exe -f !FromEmail! -t !Recipient! -cc !CCRecipient! -u "!Subject!" -m "!Message!" -v -s !Server!
rem ** force execution to quit if check fails
EXIT /B %ERRORLEVEL%
)
call %batFile2%
if %ERRORLEVEL% NEQ 0 (
echo.
set Message=Execution of %batFile2% failed with error message %ERRORLEVEL%. Examine the logs and fix any issues before next run.\n\nAt your service\nAdmin
echo Start: Send Email
c:\APPS\sendemail.exe -f %FromEmail% -t %Recipient% -cc %CCRecipient% -u "%Subject%" -m "%Message%" -v -s %Server%
rem ** force execution to quit if check fails
EXIT /B %ERRORLEVEL%
)
call %batFile3%
if %ERRORLEVEL% NEQ 0 (
echo.
set Message=Execution of %batFile3% failed with error message %ERRORLEVEL%. Examine the logs and fix any issues before next run.\n\nAt your service\nAdmin
echo Start: Send Email
c:\APPS\sendemail.exe -f %FromEmail% -t %Recipient% -cc %CCRecipient% -u "%Subject%" -m "%Message%" -v -s %Server%
rem ** force execution to quit if check fails
EXIT /B %ERRORLEVEL%
)
call %batFile4%
if %ERRORLEVEL% NEQ 0 (
echo.
set Message=Execution of %batFile4% failed with error message %ERRORLEVEL%. Examine the logs and fix any issues before next run.\n\nAt your service\nAdmin
echo Start: Send Email
c:\APPS\sendemail.exe -f %FromEmail% -t %Recipient% -cc %CCRecipient% -u "%Subject%" -m "%Message%" -v -s %Server%
rem ** force execution to quit if check fails
EXIT /B %ERRORLEVEL%
)
EXIT /B %ERRORLEVEL%
It appears that none of the lines of code are executed that follow the command call %batFile1%
For information purposes, this is how the %batFile1% exits:
EXIT /B 254
so that should be coming back with %ERRORLEVEL% 254 every time. the test email that I send just before calling batFile1 works fine.
#echo off
setlocal EnableExtensions
rem ** setup so it logs itself **
set "parent=%~dp0"
set "me=%~n0"
set "LOGFILE=%parent%logs\%me%.log"
if exist "%LOGFILE%" del "%LOGFILE%" /f /s /q
call :LOG > "%LOGFILE%" 2>&1
exit
:LOG
setlocal
echo ParentDir: %parent%
echo ProgramName: %me%
echo.
rem ** script variables **
set batFiles="%parent%FILE1.bat" "%parent%FILE2.bat" "%parent%FILE3.bat" "%parent%FILE4.bat"
set "FromEmail=server#domain.com"
set "Recipient=adminuser#domain.com"
set "CCRecipient="
set "Subject=Email Subject"
set Message=There was an error in running nightly batch files.^
Please look at the logs to determine which batch file is causing a problem.\n\n^
At your service\n^
Admin
set "Server=smtp.domain.com"
set "Port=25"
rem ** Send email test **
echo.
echo Start: Send Email
set Message=Debug test code
c:\APPS\sendemail.exe -f "%FromEmail%" -t "%Recipient%" -cc "%CCRecipient%" -u "%Subject%" -m "%Message%" -v -s "%Server%"
rem ** run bat files and capture error message **
for %%A in (%batFiles%) do (
call :EMAIL %%A
if errorlevel 1 exit /b
)
exit /b
:EMAIL
setlocal
echo.
call "%~1"
if errorlevel 1 (
echo %errorlevel%
set "exitcode=%errorlevel%"
) else exit /b
rem ** Send email **
if "%~n1" == "FILE1" (
set "Message=Debug test code %exitcode%"
) else set Message=Execution of '%~1' failed with error message %exitcode%.^
Examine the logs and fix any issues before next run.\n\nAt your service\nAdmin
echo Start: Send Email
c:\APPS\sendemail.exe -f "%FromEmail%" -t "%Recipient%" -cc "%CCRecipient%" -u "%Subject%" -m "%Message%" -v -s "%Server%"
rem ** force execution to quit if check fails **
if %errorlevel% neq 0 echo Email send error message %errorlevel%.
exit /b
With optimizing the code some, to remove duplication etc.
It appears to be working better. I may have accidently fixed it.
Suggest checking echo %errorlevel% of the call before using
set, else %errorlevel% is of the set command.
None of the new code requires delayed expansion, so remove the
EnableDelayedExpansion setting.
Scripts are set to one variable and is used as a file-set,
in a for loop.
Many of set variable=value are double quoted to avoid any
trailing space issues. Those not, are multiline etc. that
are better without.
The Send Email code is not in a label :EMAIL which helped
to merge the duplicate code. It does a check if name FILE1
is the argument and uses a different email message to match
your original code.
It will end the script if sendemail.exe sets %errorlevel%
to not zero, which is later checked in the for loop.
If you want to exit on the called child batch-file instead,
change the last line from exit /b to exit /b %exitcode%.
Note, implicit use of exit /b is same as exit /b %errorlevel%.
If you prefer the later, update the code to you preference.
The later may require delayed variable expansion if used
in a code block i.e. (command & exit /b !errorlevel!).

What am I doing wrong in this batch file?

When I run the below batch file code, it thinks that the server address is 'dbuser' and the Database is 'False'
What am I doing wrong?
Here is the code:
#echo off
set toolspath=C:\Program Files (x86)\Folder\Application
Set ApplicationServer=00.0.00.000
Set ApplicationDatabase=dbApplication
Set ApplicationUser=dbuser
Set ApplicationPassword=abcdefg
Set ApplicationUpgradeFromPre12_5=False
REM echo "Attaching dbApplication .. "
REM osql -S %ApplicationServer% -U %ApplicationUser% -P %ApplicationPassword% -i %ApplicationScriptsPath%\AttachApplicationDatabase.sql
REM osql -S %ApplicationServer% -U %ApplicationUser% -P %ApplicationPassword% -i %ApplicationScriptsPath%\SetDBVersion.sql
REM echo "Done."
call ApplicationUpgradeScripts.bat %%2 %ApplicationUser% %ApplicationPassword% %ApplicationDatabase% %ApplicationUpgradeFromPre12_5%
#if ERRORLEVEL 1 goto ERRORSEXIT
#Echo %ApplicationDatabase% Database Updated Successfully.
goto FINISH
:ERRORSEXIT
#Echo Error: Database Excecuted With Error. To Find out Exact Error see file ErrorLog.log
exit /B 1
goto ENDBUILD
:FINISH
#Echo All Databases Excecuted Successfully.
exit 0
:ENDBUILD
pause

BATCH - wait for file to be complete before picking up

I have a command that watches a certain folder for new files. These files are created by a video transcoder so are locked and keep growing in size till completion.
#echo OFF
:loop
if exist "E:\OUT\*.mxf" (
for %%i in ("E:\OUT\*.mxf") DO (
C:\bmx\bmxtranswrap -o "E:\DPP_create\DPP_OUT\%%~ni.mxf" -t as11op1a -y 09:59:50:00 --afd 10 "%%i"
ping -n 5 localhost >nul
del "%%i"
)
)
ping -n 5 localhost >nul
goto :loop
Is there a way to only pick up files which are fully completed (Windows unlocked)? At the moment the next command is tripping up as it is attempting to open an incomplete file.
Any advise? Thanks.
As long as you are correct in that your transcoder has the file locked until it is complete, then the solution is actually simple.
Use redirection to test that you can open the file for writing, but don't modify it. Only process if the redirection succeeded.
Note:
You don't need your outer IF statement.
You can use an infinite FOR /L loop instead of a GOTO loop
I don't understand why you need a delay before your DEL, but I preserved it anyway.
#echo OFF
for /l %. in () do (
for %%i in ("E:\OUT\*.mxf") do 2>nul( (call )>>"%%i" ) && (
C:\bmx\bmxtranswrap -o "E:\DPP_create\DPP_OUT\%%~ni.mxf" -t as11op1a -y 09:59:50:00 --afd 10 "%%i"
ping -n 5 localhost >nul
del "%%i"
)
ping -n 5 localhost >nul
)

Batch file : Extract substring based on presence of another substring

I am sending various parameters to batch file. In that i need the parameter next to the "-l" ..
For example : when calling the .bat
Test.bat sampl.exe -s ssss -m mmmm -l path -k kkkk -d dddd
In this i need to extact "path" based on the presence of -l. In general, I need to extract the next parameter to "-l". Is there a way i could do it ? Please help
Below there is a standard code for Batch files like this one. The code is even simpler if variable names are the same than the switches, i.e. set s=ssss set l=path etc.
#echo off
if "%1" neq "" goto getParams
rem A simple description of how to use this Batch file goes here, ie:
echo Test.bat progname [-s ssss] [-m mmmm] [-l path] [-k kkkk] [-d dddd]
goto :EOF
:getParams
rem Set here default parameter values, ie:
for %%a in (s m l k d) do set %%a=
set progName=%1
:shift
shift
for %%a in (s m l k d) do if /I "%1" equ "-%%a" goto getParam
goto main
:getParam
set %1=%2
shift
goto shift
:main
rem Run here the program, ie:
cd %l%
%progName% %s% %m% %k% %d%
I hope it helps...
The idea is to loop through the list of parameters and if -l is found then call another section that then extracts the next parameter.
The SHIFT, removes the first parameter from the list of available parameters. eg:
If you ran: sampl.exe -s ssss -m mmmm -l path -k kkkk -d dddd
The available parameters would be = -s ssss -m mmmm -l path -k kkkk -d dddd\
If in the script you executed SHIFT, then the available parameters would be = ssss -m mmmm -l path -k kkkk -d dddd
See the code example below:
#ECHO OFF
SET path=
SET mmm=
SET sss=
SET ddd=
REM Loop through passed parameters
:LOOP
IF [%1]==[] GOTO LOOP_END
IF [%1]==[-s] #CALL :PROCESS_S %2
IF [%1]==[-m] #CALL :PROCESS_M %2
IF [%1]==[-l] #CALL :PROCESS_L %2
IF [%1]==[-d] #CALL :PROCESS_D %2
SHIFT
GOTO LOOP
:LOOP_END
REM call your actual end result here.. Once the batch file gets here, the variable path would have been set if there was a -l <my path> passed, otherwise it would be empty
cd %path%
runmyprogram.exe %sss% %mmm% %ddd%
GOTO:EOF
REM Define your methods down here.
:PROCESS_S
IF [%1]==[] GOTO:EOF
SET sss=%1
SHIFT
GOTO:EOF
:PROCESS_M
IF [%1]==[] GOTO:EOF
SET mmm=%1
SHIFT
GOTO:EOF
:PROCESS_L
IF [%1]==[] GOTO:EOF
SET path=%1
SHIFT
GOTO:EOF
:PROCESS_D
IF [%1]==[] GOTO:EOF
SET ddd=%1
SHIFT
GOTO:EOF

Resources