Call to .cmd file causes exit from parent .cmd file - windows

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

Related

Windows cmd START batch file in new console with quoted arguments

Note: A solution is posted below.
Problem:
When required to start a batch file (cmd script) (i.e. CALLEE.CMD) in a new console window, from within another batch file (i.e. CALLER.CMD) , the obvious choice would be to use the internal START command: START "" "%~DP0CALLEE.CMD".
However, if we need to pass quoted parameters to CALLEE.CMD, such as START "" "%~DP0CALLEE.CMD" "ARGUMENT_1", you get an error such as 'CALLEE.CMD" "ARGUMENT_1' is not recognized as an internal or external command,
operable program or batch file.
At first glance, it's not obvious why this command should fail, as the requirements for calling the START command seem to be met. This question is posted because the reason for failure is not immediately apparent, and others may find the reference useful.
So, why is this command failing, and how to resolve the issue?
What is happening here, is that when the START command detects the command to be invoked is either an internal command (internal to cmd.exe) or a batch file, it will invoke cmd.exe to handle the command (cmd.exe /K ... will be used). The additional arguments passed to START will be translated and passed to cmd.exe. When this happens, the rules change: cmd.exe expects the command and arguments to be quoted differently from START, so this has to be taken into account when writing the original command.
The quoting for cmd.exe is documented elsewhere, such as:
correct quoting for cmd.exe for multiple arguments
http://ss64.com/nt/cmd.html.
So, to start a batch file, with quoted arguments in a new console window, we could do as follows:
START cmd.exe /K ""%~DP0CALLEE.CMD" "ARGUMENT_1" "ARGUMENT_2""
Of course, this problem only occurs if you need to quote the arguments, either because a called program expects it or if there are spaces in the argument.
Also, as a plus, if you don't require the new console window to remain open after finishing the batch file, you can substitute the switch /K with /C.
The requirement for always needing to provide a window title when calling a quoted command is avoided here, but if you do require to prefix the title of the new console window, you can do as follows:
START "<Title>" cmd.exe /K ""%~DP0CALLEE.CMD" "ARGUMENT_1" "ARGUMENT_2""
Example code:
CALLEE.CMD
#ECHO %*
#PAUSE
CALLER.CMD
#START "<Title>" cmd.exe /C ""%~DP0CALLEE.CMD" "ARGUMENT_1" ARGUMENT_2 "ARGUMENT_3""

Strange redirect in Batch/Powershell polyglot

While attempting to rewrite a batch file, I was looking into the possibility of using powershell. The main issue that I had with it was that .ps1 files aren't executable by default. I found a solution here, which I'll copy below, but I'm very confused about the syntax on the first line:
<# : batch script
#echo off
setlocal
cd %~dp0
powershell -executionpolicy remotesigned -Command "Invoke-Expression $([System.IO.File]::ReadAllText('%~f0'))"
endlocal
goto:eof
#>
# here write your powershell commands...
Here's what I know from testing:
The space between <# and : is required, though there can be multiple.
It can also have a number 0-9 beforehand, such as 3<# :, which makes me suspect that there's some weirdness involving redirects and labels.
The text after the colon is ignored and not necessary
If I add a command before it, such as git <# : batch script, the shell shows that it tried to evaluate git : batch script 0<# and can't find the file specified
Changing the # to a valid filename makes the complaint go away (naturally)
Attempting to run the line in an interactive session actually causes it to complain about not being able to find the file specified, but running it from a script (even if it's the only line in the .cmd file) silently succeeds
That last bullet is the part I'm trying to figure out. What's different about the environments? My understanding was that part of the issue was that running a bat file is parsed as if each line were manually entered. Why doesn't it complain about # being an invalid file when called via a script?
"...running a bat file is parsed as if each line were manually entered."
No, parser rules are sometimes different between command line and batch file and in this case the difference is critical.
It complains about # being an invalid file in command line, and not in batch file, because the <# : construct is (to the batch parser) just a redirected label. The same kind of label you use in goto :label or call :label.
That means that the redirection, that is not executed in batch file as the "command" associated to the redirection is a label, is executed in command line as you can not have a label in a command line.
The trick is that you need a valid construct for both, powershell and also batch.
For powershell only th <# is important to open a multiline comment.
For batch you need something that will be valid code but is invisible inspite of the echo on state.
Therefore a colon is perfect in this situation, as label lines will not be shown, even with echo on.
You can see the result of the parser, when you replace the colon with REM.
<# REM Batch script
Output:
c:\Temp>REM batch script 0<#
The # is a valid filename, but the file itself is never accesed.

Why does console output keep self-referencing batch script from exiting cleanly?

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.

Batch file: How to redirect output from .exe with parameter?

I am trying to write a batch file to run a .exe with a parameter and that gives and output in .csv
I wrote:
start "" "C:\Users\Me\Desktop\AnalysisSoftware\Video.exe" S1.avi>S1.csv
This command is working but the created .csv file is empty. What's wrong?
I also tried with ^ like that:
start "" "C:\Users\Me\Desktop\AnalysisSoftware\Video.exe" S1.avi^>S1.csv
Not working too...
Thank you
Cec
The start command starts the command in another process and so the output is not captured, instead you are capturing the output of the start command, which is nothing.
What you need is
start "" "cmd /c C:\Users\Me\Desktop\AnalysisSoftware\Video.exe S1.avi>S1.csv"
The distinction here is that the redirection operator is within the quotes. In your example above the redirection operator was outside the quotes and so it captured the output of the start command instead of the Video.exe. Note you also need to use cmd /c at the beginning. This is because you need a shell in order to redirect the output of the Video.exe. The /c argument tells cmd to exit as soon as the command finishes executing.

is it possible to distinguish when shell is run from command line or from other shell?

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

Resources