Catching return value from Tcl in batch - batch-file

This is my Tcl script
return 2
It is doing nothing, but just returning value 2. Now my batch script call this tcl file called foo.
tclsh foo.tcl
The return value can change from time to time and I need to get this value in the batch file. Is thr a way to do that. I am new to batch commands, so I dont have much idea about this. I tried if-else loop, but it gives syntax error. Any idea would be appreciated.

To get an external caller of Tcl to see a result code, you need exit and not return:
# In Tcl
exit 2
Then your caller can use the exit code handling built into it to detect. For example with bash (and most other Unix shells):
# Not Tcl, but rather bash
tclsh foo.tcl
echo "exit code was $?"
On Windows, I think it's something to do with ERRORLEVEL but it's a long time since I used that platform for that sort of thing. I just remember it being annoying…

It appears %ERRORLEVEL% is what you want:
C:\Users\glennj>tclsh
% exit 3
C:\Users\glennj>echo %ERRORLEVEL%
3

Related

Store return value of a compiled exe into a batch variable

I've read topics here and on the internet about the argument but the solutions offered do not work for me.
Firstly I'll tell you what I want to do:
I have a compiled c file (.exe) that returns various integers depending on the situation.
I want to store said return value in a variable in batch. From what I've read, there's no specific command to do this (like 'v=$?` in shell that assigns to the variable the last returned value), but I found instead a workaround that uses the for loop.
The code I found is the following:
FOR /F "tokens=*" %%a in ('test.exe') do SET OUTPUT=%%a
echo %OUTPUT%
But when I run the batch file, I get ECHO is off.
I'm a complete beginner in batch, I simply searched "store return value in batch" and the code above is what got spit out. Any insight or help on the problem is appreciated, thanks in advance!
Answer given by Mofi
Dillon Wreek wants the exit code (also called exit value, return
value, return code or in CMD syntax errorlevel) of test.exe and not
the output of the text.exe written to handle stdout. So all needed by
Dillon Wreek is a batch file with first line #echo off, second line
test.txt, third line echo %errorlevel% resulting in writing into
console window the value 1 or 2 or 3 or ... 12 and fourth line pause
to see the output on double clicking on batch file.
Basically:
test.exe
set var=%errorlevel%
echo %var%

Using call <file.bat> results in "sleep is not recognized as an internal or external command.."

I have a script that calls other commands in a for loop:
for %%x in (%CMDS::= %) do (
call C:\%%x %1%
echo "%%x complete"
)
However, running this results the console spitting out :
'sleep' is not recognized as an internal or external command,
operable program or batch file.
This is because the files i loop through and run have these commands in them. Why is it that if i run these files one by one they work, but when chained using call they don't? I can sleep in my terminal outside of this script..
Regards
Thanks to another answer, I solved this error by replacing sleep 5 in my .bat file with:
powershell -Command "& {sleep 5}"
Works fine now. Better still, also tested Stephan's suggestion:
timeout 5
Simpler, and shows a nice message like
Waiting for 0 seconds, press a key to continue ...
Note that some Windows versions require the /t option to define the time.
timeout /t 5
There is no sleep command in batch. That's why you are getting this error.
EDIT:
There is no sleep command in Windows CMD or Batch. BUT: as you can use the command in your console, I suppose there might be a script or a program called sleep. This script or program might be situated in your working directory or in some other directory included in your %PATH% variable. If this is the case, it's possible that your script gives you this error because of a path issue.
Say, you are in C:\SomeFolder and there is a sleep.exe in there. You are calling another script or command which changes the current directory to D:\AnotherFolder. Now another script or command tries to execute your mysterious sleep command assuming the working dir to be C:\SomeFolder but as you are in a different folder (D:\SnotherFolder) now, sleep can't be found. Further, when using call the variable scope of the calling script becomes also the scope for the called script. So it's also possible that variables are being overwritten by different scripts. Such a variable might contain the path to your sleep command. This could also cause an error.

Batch file: pass a block of commands instead of a script.tcl

I run a .tcl script using a .bat file as per the simplified example below:
script.tcl
set a "this is the script"
puts $a
script.bat
echo off
set tclpath="C:\tclsh.exe"
set filepath="C:\script.tcl"
%tclpath% %filepath%
I wonder whether I can include in the .bat file the commands of the .tcl script, so instead of having two files I just have one .bat file that runs tclsh.exe and passes the commands to the tcl shell.
Is this possible? and how can I do it?
For many things, there are pages on the Tcler's Wiki that can be looked to for interesting things. In particular, this old page has some really useful techniques. As you read through, you'll see a history of techniques tried. They depend on the fact that Tcl commands can be prefixed with :: usually (marking them as a weird label in the batch file language) and you can comment out blocks of code in Tcl with if 0 (with Tcl not parsing the contents, beyond ensuring that it is brace-balanced, which code usually is).
The best technique is one that doesn't just make the code multilingual, but also makes it easily readable. Preserving readability is the key to not going crazy.
::if 0 {
#rem This code in here is pure batch script
echo off
set tclpath="C:\tclsh.exe"
%tclpath% "%~f0" %*
#rem Put this at the end; it means terminate since the “eof” label is end-of-file
#goto eof
}
# This code is the pure Tcl code
set a "this is the script"
puts $a
The other bits to be aware of:
"%~f0" — This gets the full path to the “zero-th argument”, which is the name of the script you're running.
%* — This is all the remaining arguments. It's a good idea to pass them on, and you can access them from Tcl using the list in the global argv variable.
I wonder whether I can include in the .bat file the commands of the .tcl script, so instead of having two files I just have one .bat file
that runs tclsh.exe and passes the commands to the tcl shell.
Easy peasy. . .
You can use a CALL to a subroutine in a batch script that will append the commands to the dynamically created script file which you specify with the set filepath variable.
This way you have everything in the batch script and you do not need to worry about the tcl script file other than ensuring the :tclshScript routine that creates it has the correct syntax, etc.
You essentially build the tcl script logic with batch ECHO commands and it'll create it per run.
Use caution with special characters though as the carat ^ symbol may be needed to escape certain character to the tcl script if batch interprets those otherwise or you notice an issue.
echo off
set tclpath="C:\tclsh.exe"
set filepath="C:\script.tcl"
IF EXIST "%filepath%" DEL /Q /F "%filepath%"
CALL :tclshScript
%tclpath% %filepath%
EXIT
:tclshScript
ECHO set a "this is the script">>%filepath%
ECHO puts $a>>%filepath%
GOTO EOF
Further Resources
CALL
ECHO
Escape

Batch command exit

I have to rewrite an old Batch file into Powershell script.
one line is
directory1\nunit-console.exe file1.dll /xml:results.xml
exit %%ERRORLEVEL%%
I am a bit confused about the "exit %%ERRORLEVEL%%" bit
Normally, just type in command line >>exit and enter. It will shut the screen.
What does %%ERRORLEVEL%% bit mean?
thanks
In "DOS" shells (i.e. COMMAND.COM, CMD.EXE), variables are defined as %VAR%. %ERRORLEVEL% represents the return value of the last-executed command; it is like $? in Bash or Perl.
In this case, exit %%ERRORLEVEL%% appears to be an attempt to exit the batch script with the return value from the call to nunit-console.exe. (This script looks quite old, as both exit and the need for double-percent symbols has changed slightly between MS-DOS and the later shells in Windows 2000 and later.)
See this page for a discussion of how exit is used in the various shell versions.
This MS KB article talks about using the % character in batch files. It was written for MS-DOS, but most of the same principles apply to later shells.

To "Call" or "Not to Call" a batch file?

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!

Resources