If from inside a bat file you called another batch file but still had a few remaining operations to complete, how can you make sure that the call to first bat file will after completion or error, will return to the file that called it in the first instance?
Example:
CD:\MyFolder\MyFiles
Mybatfile.bat
Copy afile toHere
or
CD:\MyFolder\MyFiles
CALL Mybatfile.bat
COPY afile toHere
What is the difference between using CALL or START or none of them at all? Would this have any impact on whether it would return for the results of the copy command or not?
As others have said, CALL is the normal way to call another bat file within a .bat and return to the caller.
However, all batch file processing will cease (control will not return to the caller) if the CALLed batch file has a fatal syntax error, or if the CALLed script terminates with EXIT without the /B option.
You can guarantee control will return to the caller (as long as the console window remains open of course) if you execute the 2nd script via the CMD command.
cmd /c "calledFile.bat"
But this has a limitation that the environment variables set by the called batch will not be preserved upon return.
I'm not aware of a good solution to guarantee return in all cases and preserve environment changes.
If you really need to preserve variables while using CMD, then you can have the "called" script write the variable changes to a temp file, and then have the caller read the temp file and re-establish the variables.
call is necessary for .bat or .cmd files, else the control will not return to the caller.
For exe files it isn't required.
Start isn't the same as call, it creates a new cmd.exe instance, so it can run a called batch file asynchronosly
The `CALL' statement was introduced in MS-DOS 3.3
It is used to call other batch files within a batch file, without aborting the execution of the calling batch file, and using the same environment for both batch files.
So in your case the solution is to use CALL
Okay, I actually didn't even really think about the fact that if you call a batch (regardless of the 'type', i.e. '.bat', or '.cmd') that it won't return if you don't use call.
I've been using call myself though for a different reason that I am actually pretty surprised that no one else has brought up. Maybe I missed it. MAYBE I'M THE ONLY ONE IN THE WORLD WHO KNOWS!! :O
Probably not, but I'm going to drop this knowledge off here because it's super useful.
If you use call you can use binary logic operators to decide how to proceed based on the ERRORLEVEL result. In fact, I always was flabbergasted on how && and || existed in DOS and COULDN'T be used this way. Well, that's why.
The easiest way to test this is to create a return.cmd with notepad, or from the command prompt like so:
c:\> type con >return.cmd
You will now notice the cursor goes down to the next line and hangs. Enter:
#exit /B %1
And then hit ENTER, and then CTRL-Z and that file will be created. Good! You may now feel free to try the following two examples:
call return.cmd 0 && echo Huzzah! A Complete Success! (Or cover up...)
call return.cmd 123 || echo Oops! Something happened. You can check ERRORLEVEL if you want the tinest amount of additional information possible.
So what? Well, run them again with the 0 and the 123 swapped and you should see that the messages DON'T print.
Maybe this multi-line example will make more sense. I use this all the time:
call return.cmd 0 && #(
echo Batch says it completed successfully^^!
) || #(
echo Batch completed, but returned a 'falsey' value of sort.
call echo The specific value returned was: %ERRORLEVEL%
)
(Note the 'call' in the || section before the second 'echo'. I believe this is how people got around not having delayed expansion back in the day. If you DO have delayed expansion enabled (via. setlocal EnableDelayedExpansion inside a batch OR launch a command prompt with cmd /v:on then you can just do !ERRORLEVEL!.)
... This is where I have to apologize and say if you have if ERRORLEVEL trauma in your past you should stop reading. I get it. Trust me. I thought about paying someone on fiverr to remotely type this for me, but for completeness sake I'm just going to take one for the team and mention that you can also do the following to check errorlevel:
if ERRORLEVEL 123 #echo QUICK! MOTHERS, COVER YOUR CHILDREN'S EYES! FINGERS ARE BEING UNDONE! :'(
If you've never typed that before then GOOD! You will live longer without having to read up why exactly you aren't getting the results you expect. Cruel is the word you're looking for, not 'quirky'.
The important part that I really want to get across however is that if you try this and DON'T use 'call' it will ALWAYS execute the 'true' branch. Try it for yourself!
If I'm missing something, or you know a better way to do this, please let me know. I love learning stuff like this!
Additional information I mentioned:
I have known for quite some time that you can put redirects BEFORE commands like so:
>nul echo. This won't be displayed!
But I accidentally discovered the other day by being a dumdum that you can apparently also do:
echo A B>file.txt C
And was REALLY surprised to find a file.txt which consisted of "A B C". It appears yo can place them ANYWHERE, even inside the command. I've never seen anyone do this, nor mention it, but I HAVE seen people mention that you can prefix a line with them.
Maybe it's a bug exclusive to Windows 10 or something. If you have another version and wanna try it out and let me know I'd be interested in what you find out.
Stay nerdy!
Related
I need help with understanding the following Batch script structure:
This is named Profile_something_schedule.bat
call somePath\lib.cmd :someLabel reqPath
call somePath\lib.cmd :someLabel reqKey
%reqPath% "%~someFileName" /vv_pwd=%reqKey% /bProfile_something_schedule /min
I have a lot of difficulty understanding why this script works.
I do not know why the 3rd line is valid. The behavior produced is that the someFileName is run. I understand it as starting the file as a process. Then why isn't the start command needed? I don't see any batch documentation saying you can simply run a file by writing its pathed filename.
I do not understand the syntax of "%~someFileName". From online searching about it almost every source shows you the batch call parameter table, saying things like %~1 expands %1..., %~f1 expands %1 some other way, etc. All of them involve some kind of number from 0 to 9 to correspond to the parameter position. However, I cannot find any specification of %~someString being legal. There is no parameter positional information from the someFileName string, it is a filename.extension string. Still, it is quite likely this line is trying to run this format.
What does "/vv_pwd=%reqKey% /bProfile_something_schedule" mean? In the lib.cmd that was called previously, there were variables reqPath and reqKey and I am quite certain it is trying to pass the value of reqPath and reqKey from the lib.cmd into the variables here and then I guess it is trying to use the reqKey value as a parameter, which is a password required to run the file.
Inspecting the file, it contains some script of some paid software specific format, it only has variable name v_pwd inside but not vv_pwd. I do not know what the /bProfile_... is for. The part without the /b is exactly this batch file's name. But together with the /b I don't know what it means. The /v and /b look like some kind of options to me but I cannot see any specification explaining as there is no command beginning line 3 just some path. I guess the /min option refers to starting window minimized which is an option for the command start, yet there is no option of /v. The /B in start means to start application without creating window, which is quite unnecessary to have /min if you are not going to create a window in the first place. And it doesn't make sense to use /B directly followed by some string of Profile_something_Schedule.
FYI, the lib.cmd starts with call %*, which I would consider as trying to call all passed parameters and assuming those parameters are actually batch files that can be called.
Another thought I have is that the 2nd line call connects with the 3rd line so the 3rd line may not need a command. But I can't make sense of it. The someFileName is not of the Batch extension so I doubt it can be called as the call doc says it is for batch programs. If I want to run non-batch programs I need to use start right?
Would greatly appreciate your help!
The variable pathext contains a semicolon-separated list of executable filenames that may be appended as an extension to myexecutable. if the first string on a batch line is not a cmd internal command (like set, for etc.) then cmd tries to find myexecutable + each of the extensions in pathext in turn, first in the current directory, and then in each directory in the path (another semicolon-separated list of directories) and runs the first name found, or fails if none are found. That first string may also have an Associated extension, which then runs the application with which the extension is associated (like .txt runs notepad by default)
Neither do I, and I can't see that even knowing what the actual strings being executed by %reqPath% are would assist. See for /? from the prompt for more documentation on other ~ operators - or search SO for thousands of uses.
vv_pwd=%reqKey% : %reqKey% is replaced by the value of the variable reqKey evidently returned by the previous line. / is used in Windows to mean "here's a switch parameter for the executable", so evidently /vv_pwd=[the contents of reqKey], /bProfile_something_schedule and /min mean something to the executable %reqPath%. Quite what is anyone's guess.
The fact that lib.cmd's first line is call %* would mean that lib.cmd contains a library of routines. Since each call you have shown is of the form :string1 string2 then the resultant command executed would be call :string1 string2. call :string1 will call the routine contained within "lib.cmd" with the label string1: supplying string2 (and presumably optionally string2 string3... as parameters. Evidently, string2 is the name of the variable into which lib.cmd places the required data.
Without the :, string1 would be any executable that cmd can locate using the method in (1). It does not have to be a batch, but commonly is a batch.
Something like: (This is an example)
call :sub
echo comes first.
goto end
:sub (
echo This part
)
:end
Maybe? If so, what would be the proper way to format it?
I'm aware that I can just call .bat files, but I'd prefer to keep this whole thing in one program.
I'd like this to be accessible throughout multiple parts of the program, so a regular call wouldn't suffice because I want the program to go back to wher it left off each time this is called.
Very close.
Using call :label you can indeed call the same batch file as a separate process, as if it were a subscript. Using goto :eof you can return control to the main script, which will continue at the place it was.
It should also work when the subscript just ends, so, your code should actually work, except for the parentheses, which are invalid the way you use them. Just remove them and you script should work. It should echo:
This part
comes first.
I'm making a batch program that is supposed to be like a simplified(-ish) command prompt for commands that I make. I am wondering, though, about this line of batch coding that I have narrowed down as a fatal error (causes the cmd.exe running the program to close) causing line: echo One(1) application is within this folder. When I attempt to go to that section via inputting the command to run that section it states: application was unexpected at this time followed by immediately closing. I have also tried replacing "application" with "program", to no avail. I was wondering: What are all of the mysterious echo parameters/rules. for instance echo text >> name.extention is possible, but typing echo /? does not give you anything besides #echo on/off and echo text.
I believe it is something to do with the (), as in other languages it is used to call a function with the arguments within the (), but I do not understand why it would be this, as it is not running the "One" function because it is inside an echo, meant only to display it literally. Also, I don't believe batch has functions that can be called like this (I've only seen them in VB, lua, java, and C++ [of the ones I use])
If anyone knows why the program failed at this line, and/or (preferably and) all of the other hidden echo rules, please list them out for us; they really need to be known (I've seen so many questions on this website [and others] specifically about the echo command).
Within a block statement where you have if expression (whatever1) else (whetever2) then you need to escape a closing parentheseis ) with a caret ^ thusly : ^)
The escape tells batch that the ) is NOT the termination of the then/else
I have a batch file that encounters several errors. These errors require the command prompt to be forcefully closed. Which causes me to have to open the file again to fix the issue.
Due to the nature of this application it is required to run all the time.
I'm looking for a way to automate the file to restart when it encounters an error. Is there a command I can do this with?
Could you please describe in detail and why the command accomplishes such a resolution?
Update:
What I would recommend to accomplish your goal, would be to turn your batch into a Service. (Documentation here) By converting your batch into a Service it no longer becomes subject to users being logged in, permission issues, it will run as a SYSTEM ACCOUNT. This in itself can alleviate a lot of anger for the process.
After you've completed that, you can write a batch file that ensures that your Service is indeed running. Your current issue, is it doesn't automatically restart. Well, a Service always runs- Even if it has an error it will still attempt to run.
Which means unless it has a Fatal Exception your Service should always work- But for certainty you can create a batch that will ensure your Service is running.
An example:
:START
timeout 3600
for /F "tokens=3 delims: " %%H in ('sc query "MyServiceName" ^| findstr "
if /I "%%H" NEQ "RUNNING" (
NET START "MyServiceName"
REM Service has Started...
)
)
GOTO START
So in theory every 3,600 seconds it will test if your Service is running, if it isn't it will start the Service for you.
Important:
This is more the proper way to resolve your issue, rather then circumvent it. However, as I noted your batch should still implore Exception Handling to ensure your application doesn't fall into an unusable state. This still isn't the best way, as it should implore Exception Handling and Verification to test against it's state.
As I mentioned before, you have a lot of methods to solve your issue. However, your thinking in a Linear Mindset. Which means:
Execute Command, Goal Guaranteed.
If I do this, this happens.
Essentially based on the minimal example I saw, it looks like you've created an infinite loop to continually execute your command. My question to you: When your loop has an error, how can it continue to run?
You've already stated that it happens in random areas- Nothing is random, those are more then likely areas that require some verification / testing to ensure it remains in a proper state. The faster your identify the potential problems, the more effective your program can run with no errors.
Hopefully that helps-
What exactly does your batch application do?
The reason I ask is because you can circumvent the issue with Windows Task Scheduler which allows you to configure some parameters to auto start and auto open particular applications based on your specified criteria. Will it be ideal? Will it truly automate to your needs- More then likely not.
As mentioned above by GolezTrol, the cause of your error will be the more important aspect to resolve your issue. Based on your remark
The errors are different each time, to be honest.
That could be an indicator that the batch script doesn't adhere to testing but rather assuming it successfully completed. Without any underlining information such as:
Function
Code Example
Where an error occurred, and during what task.
It makes it relatively difficult to point you in the proper direction. One thing that I would consider is IF. This is a fundamentally basic task but is quite important-
if(Directory.Exists(dirName))
{
// Do This
}
else
{
// Do This
}
I find the C# outline an easier method to understand the purpose of the IF. You can actually implement something similar in your batch. You would accomplish it like this:
if exist { insert file name } (
rem file exists
) else (
rem file doesn't exists
)
or you can accomplish it like this:
if exists c:\myFile.bat notepad c:\myFile.bat
If C:\myFile.bat exists, then open notepad. The reason this is an important is because if the variable doesn't exists, then it can not be affected. This allows your application to essentially make decisions in a very primitive manner.
You have quite a bit of flexibility- There are a lot of examples on this topic because batch programming has been around for a very, very long time. Another alternative would be to eventually move to Powershell. It will have access to the Windows Management Interface (WMI).
Hopefully this points you in the right direction, without more information our answers may not be much help.
I believe, that easiest way is to create one more .bat file with GOTO statement:
#echo off
:startover
echo (%time%) App started.
call "c:\app.bat"
echo (%time%) WARNING: App closed or crashed, restarting.
goto startover
Possibly this will fix your problem:
http://nssm.cc/usage
Basically what it does is you adding some bat file to nssm and making it a service.
In "Action on exit" part it says:
To configure the action which nssm should take when the application exits, edit the default value of the key HKLM\System\CurrentControlSet\Services\servicename\Parameters\AppExit. If the key does not exist in the registry when nssm runs it will create it and set the value to Restart.
On a cmd prompt or bat file, I issue the following:
start textpad myfile.txt and it works fine.
If the program textpad does not exist on the computer, then an error sound and a popup occurs which the OK button must be pushed.
I desire to trap this error so that I could do something like
start textpad myfile.txt || start notepad myfile.txt
where the || implies that if the start of textpad is not successful, then the start of notepad should occur. HOWEVER, I still get the error sound and requirement of hitting OK.
My intent is to avoid the sound and the requirement of any user intervention.
I have also tried the following bat approach below, to no avail.
start textpad
if not %ERRORLEVEL% == 0 GOTO END
start notepad
:END
Any help would be great.
thanks
ted
You can use the following little snippet to find out whether the program you intend to launch exists:
for %%x in (textpad.exe) do set temp=%%~$PATH:x
if [%temp%]==[] echo Didn't exist.
But may I suggest that you simply use
start foo.txt
instead of forcing a specific editor onto the user? File type associations are there for a reason.
I do not believe you will find a way to make that work. Perhaps look for the existence of textpad.exe on the machine? If you can predict what directory it would be loaded from, this should be pretty easy using IF EXIST.
There are some techniques to detect the presence of a specific tool, but this only works for command line tool, or with GUI applications also supporting command line options.
For these tricks, take a look at this page.
"/wait" parameter would do the trick for you..
START /wait NOTEPAD.EXE SOME.TXT
echo %ERRORLEVEL%
# This gives zero as output.
START /wait TEXTPAD.EXE SOME.TXT
echo %ERRORLEVEL%
# This gives non-zero output.
You probably already have an answer, but my over-sized ego has forced me to post my answer.
So, this should work.
start textpad 2> nul||start notepad
This will start notepad if the command start texpad fails, while also redirecting any error message you may get from the first command.