Batch file doesn't pause after loop - batch-file

Here's my batch file:
#echo off
set rdslist=rds-instance-1 rds-instance-2
:retryaction
set /P action=Would you like to (1)start or (2)stop these instances %rdslist%:
IF %action%==1 (
set command=start
goto :start
)
IF %action%==2 (
set command=stop
goto :start
)
goto :retryaction
:start
(for %%a in (%rdslist%) do (
aws rds %command%-db-instance --db-instance-identifier %%a
))
pause
It doesn't pause after I run it, but if I place the pause before or inside the for loop it pauses.

aws is another script, not a program. When a batch script executes another batch script without using the call command, program flow is permanently transferred to that second script and does not return to the first script upon completion. When call is used, the second script is run and then flow is returned to the parent script.
Change your for loop to
for %%a in (%rdslist%) do (
call aws rds %command%-db-instance --db-instance-identifier %%a
)
so that your initial script will keep running; otherwise, the script stops after the first instance is completed.

Related

How to get a batch file only processed if it's called from another batch file?

I am coding a batch file and it needs some more files. But they files should only be able to run using the call function from another batch file. My code looks like this:
call compileData.bat
pause
I want the compilerData.bat just starts when it's called from this one, not if its just started from Explorer or something other.
Can you please help me?
I have tried to find a solution on this problem in a whole hour!
You can use a parameter.
compileData.bat:
if "%1" neq "somestring" exit /b
REM rest of your code
Another.bat:
call compileData.bat somestring
pause
I cannot think of any way that would prevent the bare "run" of the called script. Possibly that might only be done using NTFS permissions.
What you can do quickly is something like this:
MOTHERBATCH.bat
call compileData.bat SomePASSPHRASE
compileData.bat
#echo off
if not "%1"=="SomePASSPHRASE" (
echo "You can not run this script directly, please run MOTHERSCRIPT.bat."
exit /B 1
)
echo "Passphrase is correct, code is executed..."
Set an environment variable in the parent script, then if that variable is not set or doesn't have the correct value in the children, they just exit with an error message explaining they aren't intended for standalone use. You really can't prevent someone from reverse engineering the code and forcing it to run.
You could put the children in a password protected zip file and have the parent unpack it just before calling them. Then when the parent is done, it deletes the unpacked scripts.
Do all of the above.
You can use a not so well known system variable named cmdcmdline.
I will explain a brief usage for you.
For brevity's sake we will have two very simple batch files.
Parent.bat
#echo off
call compiledata.bat
And compiledata.bat
#echo off
echo %cmdcmdline%
pause
When compiledata.bat is executed on its own this variable's value is the batch file itself.
C:\WINDOWS\system32\cmd.exe /c ""C:\Batch\CALL\compiledata.bat" "
But when compiledata.bat is called from parent.bat the variable's value is that of the calling parent.bat.
C:\WINDOWS\system32\cmd.exe /c ""C:\Batch\CALL\parent.bat" "
My suggestion is putting all your batch code into a single batch file and use subroutines. Open a command prompt window and run call /? for help on how to use subroutines which is nothing else than calling a batch file being embedded in current batch file.
A simple example:
#echo off
echo Running %~f0 %*
call :compileData %*
call :WaitForUser
rem The next line results in exiting processing of this batch file
goto :EOF
:compileData
echo/
echo Running subroutine compileData with the arguments: %*
rem Exit processing subroutine compileData and continue above
rem after the command line calling the subroutine compileData.
goto :EOF
:WaitForUser
echo/
pause
rem Exit processing subroutine WaitForUser and continue above
rem after the command line calling the subroutine WaitForUser.
goto :EOF
See also Where does GOTO :EOF return to? And take a look on DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/ for the explanation on using echo/ to output an empty line.
Here's my solution:
when launched from the command line, %cmdcmdline% inherits the name from the base calling program, so it wouldn't be the name of the "middle man" calling your batch file
this is what I came up with. I had to use the "subroutine" method to get the variables properly expanded
Note: Edge Case: if you use complex paths with the batch files having the same name in different folders, you could run into an "Edge Case". If that is important to you, then you might have to further parse the file names. I'm not totally sure, it wasn't my use case so I didn't go further.
#echo OFF
setlocal EnableDelayedExpansion
call :myGetFileName "%CmdCmdLine%"
if /I "%sRet%"=="%~nx0" (
echo ************** Pause
) else (
echo ************** NO Pause
)
echo finished test
pause
exit
:myGetFileName
set "sRet=%~nx1"
exit /b

Start command does not allow the script to fully close until secondary script closes

I've got a batch script start.bat that creates a locked .lock file (basically, to verify if the script is running, by attempting to delete it) and starts a bunch of secondary looping batch scripts (they keep on running after start.bat is closed). The problem is when start.bat is closed the locked file remains locked, until ALL of the secondary scripts are closed.
Question: Are there any alternative methods to run secondary batch scripts without locking up the primary script until secondary ones are finished?
I feel like most of this code is irrelevant, but included it in case somebody wants to test it.
#echo off
set "started="
<nul >"%~nx0.lock" set /p ".=." ::Rewrite lock file with a single dot
2>nul (
9>>"%~f0.lock" (
set "started=1"
call :start
)
)
#if defined started (
del "%~f0.lock">nul 2>nul
) else (
exit //script closes
)
exit /b
:start
//irrelevant loop logic
Start pause.bat //Pause command to keep pause.bat open
//starts other batch files too
Seems like the file may still be in use?
Try:
del /F "%~f0.lock">nul 2>nul
Your problem are inherited handles. When you start a process with a redirection active, the process inherits the redirection. So, you need to keep the lock but start the processes while not keeping it.
You can try some variation of this
#echo off
setlocal enableextensions disabledelayedexpansion
rem Check if this is a lock instance
if "%~1"==".LOCK." goto :eof
rem Retrieve all the needed data to handle locking
call :getCurrentFile f0
for %%a in ("%f0%") do set "lockFile=%%~nxa.lock"
set "lockID=%random%%random%%random%%random%%random%%random%%random%"
rem Try to adquire lock
set "started="
2>nul (
>"%lockFile%" (
rem We get the lock - start a hidden instance to maintain the lock
set "started=1"
start "" /b cmd /k""%f0%" .LOCK. %lockID%"
)
)
rem Check if the lock was sucessful
if not defined started (
echo lock failed
pause
goto :eof
)
rem Launch the child processes, now detached from lock, as this cmd instance
rem is not holding it. The hidden cmd /k instance holds the lock
start "" write.exe
start "" notepad.exe
start "" /wait winver.exe
rem Once done, release the locked instance
>nul 2>nul (
wmic process where "name='cmd.exe' and commandline like '%%.LOCK. %lockid%%%'" call terminate
)
rem And remove the lock file
del "%lockFile%"
rem Done
goto :eof
rem To prevent problems: http://stackoverflow.com/q/12141482/2861476
:getCurrentFile returnVar
set "%~1=%~f0"
goto :eof
As the hidden cmd instance is hosted inside the same console than the current batch file, if you close the console, the lock is released (but the lock file is not deleted)

Oneliner to wait for a file to be created

I need a oneliner to wait for a file until it is created.
Is there a way to write that as a windows batch command? I cant have GOTO in it because I use pushd.
something like:
IF NOT EXIST \\blablabal\myfile.txt sleep(30)
The solution below is a one-liner that should be executed at the command-prompt, as requested (a Batch file is not a "one-liner"):
cmd /C for /L %i in () do if not exist \\blablabal\myfile.txt (timeout /T 30 ^>NUL) else exit
If you wish, you may insert this line in a Batch file doubling the percent sign.
I'd suppose that you want to avoid goto statement and :label inside a parenthesized code block. Use call as follows:
(
rem some code here
call :waitForFile
rem another code here
)
rem yet another code here
rem next `goto` skips `:waitForFile` subroutine; could be `goto :eof` as well
goto :nextcode
:waitForFile
IF EXIST \\blablabal\myfile.txt goto :eof
TIMEOUT /T 30 >NUL
goto :waitForFile
:nextcode
However, if you need a oneliner to wait for a file until it is created, written as a windows batch script: save next code snippet as waitForFile.bat
#ECHO OFF
SETLOCAL EnableExtensions
:waitForFile
IF EXIST "%~1" ENDLOCAL & goto :eof
TIMEOUT /T 30 >NUL
goto :waitForFile
Use it as follows:
from command line window: waitForFile "\\blablabal\myfile.txt"
from another batch script: call waitForFile "\\blablabal\myfile.txt"
Be sure that waitForFile.bat is present in current directory or somewhere in path environment variable.
cmd /c "#echo off & for /l %z in () do (if EXIST c:\file.ext exit)"
Hammers the cpu though...

How to stop a bat file from running if there is no response

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.

Batch ErrorLevel: In For loop, calling another batch, calling SQL

I've done a thorough search on this, but I can't find all of the pieces together;
I have:
BatchA runs for loop
Calls BatchB
BatchB runs a SQL script
SQL Script raises error
BatchB gets error, does (exit /b %ErrorLevel%)
Batch A checks for error
I can't make the last step work, in which BatchA responds to the exit error of batch B.
I've simplified it, and I can't even get the following to work. By not work, I mean that the GOTO statement doesn't execute. I hate for loops in batch!!!!
BatchA
setlocal enabledelayedexpansion
FOR /L %%i IN (0,1,0) DO (
:: Define variables
CALL SET TEST_NAME=%%TESTS[%%i]%%
CALL SET D_TEST=%%D_TESTS%%\%%TEST_NAME%%
CALL SET D_DB_RAW=%%D_TEST%%
CALL SET P_TEST=%%D_TEST%%\%%TEST_NAME%%.bat
:: Run preparation script
CALL ECHO. && ECHO.
CALL ECHO [INFO] TEST: %%TEST_NAME%%
CALL ECHO ----------------------------------------------------------
CALL ECHO [INFO] PREPARING THE DATABASE
CALL PUSHD %%D_PRE_TEST%%
CALL %%P_PRE_TEST_BAT%% %%D_DB%% %%D_DB_RAW%%
CALL POPD
CALL SET ERR_MSG="Error preparing the database before test: %%TEST_NAME%%"
if !ERRORLEVEL! NEQ 0 GOTO L_ERROR
BATCH B
EXIT /b 1

Resources