I can't get ExitCode to work for a VCL forms application. Here is my test application. It was created from the File / New menu in the Delphi 2007 IDE. The only change is that I added the line ExitCode := 42; at the end.
program Test;
uses
Forms,
Unit27 in 'Unit27.pas' {Form27};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm27, Form27);
Application.Run;
ExitCode := 42;
end.
Now, when I run it from the command line, %ERRORLEVEL% doesn't get set:
>.\Test.exe
>echo %ERRORLEVEL%
0
I was expected the value in %ERRORLEVEL% to be 42, but it isn't being updated.
I tried the same experiment in a console application, and that worked fine. Why isn't it working for my GUI application?
Your method of setting the exit code is fine. It's your test that's faulty.
The shell doesn't wait for GUI applications to finish running before prompting for the next command. Thus, the error level has already been established. You're checking the value at the time the command prompt was displayed, not at the time you ran the echo command.
Running programs in a batch file or command script modifies the behavior of the command interpreter to make it wait for each command to finish before running the next one, even for programs marked as using the GUI subsystem instead of the console subsystem. That's why the error level is reported correctly from batch files — the process you ran had finished before the command interpreter fetches the exit code. Without using a command script, you can try starting your program with the start command and passing it the /wait option. I'm not sure it forwards the exit code of the process it starts, though.
You can establish the exit code like you're doing, but on the console you have to test the %errorlevel% variable in the same batch to get the value.
Instead of running your commands in the command prompt, create a simple bat like this:
REM calltest.bat
.\Test.exe
echo %ERRORLEVEL%
and then, invoke your test:
>calltest
I got this in my test:
>calltest.bat
>project3.exe
>echo 47
For both, setting directly the ExitCode variable or calling Halt.
My OS is Win7 64, if it makes any difference. Printing the %errorlevel% directly from the command line prints 0.
Related
When I start a new bash shell, if I run the command echo $? as the first thing, I get 1. How can I run bash with the "default" exit code being 0?
Context: I am running msys2 in a terminal window in VS Code. If I start msys2, and then realize I didn't need a shell now and just type exit, bash exits with 1, causing VS Code to pop up an annoying warning.
Most likely something in your profile is failing and setting the status code to 1. Since status codes are overwritten by each process that runs, it'll probably be something towards the end.
Hi I am at a loss on how to run multiple commands using popen,
I am trying to automate a series of steps that are normally run on the Windows command line. The basic steps are usually run from the Windows cmd line are
Run a windows command script (.cmd) file to setup environment variables i.e C:\Program Files (x86)\appsettings\setupvariables.cmd
type in the command to connect to the database
type in the command to get data from the database
Stop connection to the database
All these commands must run in the same command line window one after another, not separate processes or separate command line windows. Instead of opening a cmd window and typing in the command I want to use python's subprocess.popen command
So far I have:
args=[]
args.append(r'C:\Program Files (x86)\appsettings\setmyvars.cmd')
args.append(r'start db on db_path="my_url"')
args.append(r'get_data_from_db>c:\temp\output.txt')
args.append(r'stop db on db_path="my_url"')
p=Popen(args,stdout=PIPE,sterr=PIPE,shell=True)
stdout,stderr=p.communicate()
if stderr:
print "you have an error", stderr
else:
print "well done you have data", stdout
This isn't quite working I can see that the first line is run i.e the setmyvars.cmd is executed, but nothing else, none of the other arguments get called, if they did I would see the results in the ouput.txt file.
How do I run a series of commands one after the other using popen. Why is it only the first command seems to be executed and none of the others
I am using python2.7 on Windows
Regards.
You have a couple of issues going on. You still have to tell popen() which program to run. Just using shell=True does not obviate the need to provide cmd.exe as the program to run. If you really want to run all of these commands with one invocation of cmd.exe, then you will need to string them together with &&.
from subprocess import *
args=[]
args.append(r'C:\Windows\System32\cmd.exe')
args.append(r'/C')
args.append(r'(echo 1 && echo 2 && echo 4)')
p = Popen(args,stdout=PIPE,stderr=PIPE,shell=True)
stdout,stderr=p.communicate()
if stderr:
print "you have an error", stderr
else:
print "well done you have data", stdout
It would probably be better to use the %ComSpec% environment variable than it would be to hardcode the location of cmd.exe. The path you have is -usually- correct. :-)
I was writing a self-referencing Windows 10 (home ed.) batch script to locate a string in a large number of log files, create a results file and, when finished, open the log file in notepad++. This process sometimes takes a few minutes hence the self-referencing part which allows me to return control to the original command window until the log file is opened (and takes focus).
However, when the second command window, started with the "start" command and the "/b" switch, includes at least one "echo" command it won't exit cleanly and requires me to press the Enter key to fully exit that "nested" command window.
I've distilled the code down to nine lines so you can hopefully see what I mean. To see it in action, save the following as "test.bat" and run it from a command prompt:
#echo off
if "%1" EQU "" call :noArgs & goto :done
echo There was at least one argument.
:done
exit /b
:noArgs
echo There were no arguments.
start "" /b cmd /c test.bat arg1
goto :eof
It will print "There were no arguments." below the prompt followed by "There was at least one argument." at the prompt and then hang, waiting for the Enter key before returning control back to the prompt.
If you remove the line:
echo There was at least one argument.
the Enter key is no longer needed for the second command shell to exit. Similarly, if the output from the echo command is redirected to a file the issue goes away. This problem also occurs without echo commands but if output is generated from EG the type command so it seems it is due to there being some form of console output. This can be easily demonstrated by commenting out both the "echo" line as well as the first line "#echo off" - with commands now being echoed to the console it again hangs before exiting.
I could get around this issue by changing the "start" call to this:
start "" /min cmd /c test.bat arg1
however any output is no longer easily visible in the minimized window so it's a poor solution.
I'd love to know why the code I posted behaves the way it does, why it won't exit cleanly without requiring the Enter key to be pressed. The only clue I have is from the "remarks" column in the matrix on this page Close and exit batch files that states, "Make sure no text is displayed in the console window to make it close automatically at the end of the batch file". However that seems to refer only to Windows 9.x versions of command.com - not EG Windows 10 nor cmd.exe.
Thanks for any input/thoughts.
-s1m0n-
You're misinterpreting the output. If I've understood you rightly, it looks like this:
C:\working\test>test
There were no arguments.
C:\working\test>There was at least one argument.
That happened like this:
C:\working\test> <---- output from first shell
test <---- input
There were no arguments. <---- output from first shell
<---- output from first shell
C:\working\test> <---- output from first shell
There was at least one argument. <---- output from second shell
<---- cursor is here
The second shell is running asynchronously - that's what start does - so the first shell has already finished the batch job and printed the next prompt by the time the second shell gets around to printing its output.
At this point, the second shell has exited, and the first shell is waiting for you to enter a command. It doesn't know that the second shell has printed anything, so it has no reason to think that it needs to reprint the prompt. But if you enter a command, it will work.
I have a .cmd file which calls another .cmd file, as follows
parent.cmd
call "C:\Program Files\Prog1\bin\dostuff.cmd" -abc="def"
After def.cmd has run, the dos window skips to the next line, showing the prompt >
The parent.cmd file has therefore completed execution, according to the command prompt. However, after the call to dostuff.cmd, the parent.cmd file is not complete and has a number of other commands to run.
dostuff.cmd sets a number of environment variables and aliases which are required for the remaining commands in parent.cmd. Therefore it is necessary that dostuff.cmd runs in the same command prompt as parent.cmd.
dostuff.cmd is written by someone else and does all sorts of things which I know nothing of. If I call some other .cmd file of my own devising in the way described above, it executes correctly and then the parent.cmd file continues executing afterwards without any problem.
Therefore something in dostuff.cmd is shutting off the processing of parent.cmd. Any ideas what this could be and how I could stop it/get around it?
Here is the parent.cmd program:
#echo off
:Begin
echo.hello
call "C:\Program Files\Prog1\bin\dostuff.cmd" -abc="def"
echo.goodbye
:End
The output is
C:\Users\cowman\desktop>.\parent.cmd
hello
dostuff.cmd text...blah blah
C:\Users\cowman\desktop>
As you can see, the echo.goodbye code is not called.
Without a listing of dostuff.cmd, we're guessing.
My patented guess would be that dostuff.cmd itself invokes cmd. If you were to respond exit to the second prompt, you should then return to the caller (unless dostuff.cmd again invokes cmd.
if the exit response terminates the cmd session and closes the window, then that's a real mystery.
This sounds that doStuff.cmd is exited by a syntax error in the batch file while redirecting stream 2 to nul.
A syntax error stops immediatly all batch instances/call stack, but the command window stays open.
I suppose the name of your batch file isn't doStuff.cmd and also the parameters are more complex than -abc="def".
As you said in the comments, the command works from the command line, but not from your parent batch, I suppose the parameters contains percent signs or carets.
If they contain percent signs, try to quadruple them.
doStuff.cmd "printf("%d",1)"
convert it to
call doStuff.cmd "printf("%%%%d",1)"
When there are carets involved try something like
set "myCaret=^"
call doStuff.cmd "a caret%%myCaret%%"
Sounds like dostuff.cmd is exiting for some reason, which will cause the whole cmd.exe to exit.
Does it have a "exit" command anywhere?, can try changing to "exit /B" to just exit the script not cmd.exe
For example I can directly call myscript.cmd or in other script I can put a line to myscript.
The reason is that if a script is run on it's own it dissapears as soon as it stop executing, so I can't see the result, so at the end I must add #pause but when I run it from another shell this causes annoyance since console window wouldn't exit that way.
So I look for some kind of 'if' condition to address this issue.
To get your script paused when double-clicked (or by dropping files on it), but terminating the usual way when invoked from console:
#echo off
echo Hello World!
:: ...your ScriptCode...
(((echo.%CMDCMDLINE%)|find /I "%~0")>NUL)&&pause
Unless you create an environment variable like Stu suggested, you're not going to find any that do what you want. You're going to need to write a small program that queries the parent process programmatically and returns a value your script can check. If you're being run from Start->run your parent will be explorer.exe. Otherwise it will be cmd.exe or some other exe.
Sample code to find the parent process can be found here.
Why not set it yourself?
SET RUNNINGFROMOTHERSHELL=YES
CALL MYSCRIPT.CMD
SET RUNNINGFROMOTHERSHELL=
In MyScript.Cmd:
IF "%RUNNINGFROMOTHERSHELL%"=="" GOTO NOPAUSE
PAUSE
:NOPAUSE