batch file call errorlevel twice - perl

I am struggling at a batch file errorlevel return issue, and could not find the answer.
Could any one give me any hints?
I have an external binary file, external.exe which read the return code (0-success, other-fail) of a batch file to decide what to do.
Within the batch file, mybatch.cmd, I wanted to run a script (perl) and return the result to the batch file.
For example, mybatch.cmd:
#echo off
myperl.pl
exit %errorlevel%
While myperl.pl is:
#!perl.exe
exit 0;
So I wanted myperl.pl to return value 0 to the batch file, and then the batch file return 0 to the external.exe file.
But external.exe didn't work as expected.
1) If I run mybatch.cmd from CLI, and then "echo %errorlevel%" from CLI, I could see it is 0.
2) If I add a line to display the return code from myperl.pl, I could see the return code from myperl.pl is exactly 0.
For example:
#echo off
myperl.pl
echo %errorlevel%
REM exit %errorlevel%
It will display 0, so the perl script returns the value exactly.
3) If I add a line to manually set the return code to 0, the external.exe works fine.
#echo off
myperl.pl
result=0
exit %result%
That is really weird. Any ideas? I could not control the external.exe, so I could not do debug on it.
In this example, the %errorlevel% is called twice:
1) Return from myperl.pl to batch.
2) Return from mybatch.cmd to external.exe. Will that be an issue?

All you have said is right: myperl.pl return a certain errorlevel, the Batch file take it and then it returns the appropriate errorlevel value. The problem is this: the Batch file, to what process return its errorlevel?
This scheme always works as a parent-children relation: a parent process execute a children one and waits for it to terminate, then the parent may take the errorlevel value returned by the children. The way to solve your problem is if the external.exe program execute the Batch file (cmd.exe) as a children! However, if you "could not control the external.exe", then there is no way to solve your problem...
How do you know that the external.exe program "read the return code (0-success, other-fail) of a batch file to decide what to do"? I think you have a confusion at this point.

Found out the root cause finally.
myperl.pl should be with fullpath, otherwise the external.exe didn't know where the myperl.pl was.

Related

How to pass integers and strings from MATLAB to a PowerShell script?

I need to automate a test. The test itself is being written (by me) in MATLAB, has 5 stages, each stage ends with setting a value to an integer (uint16_t and uint8_t) and with a message. I have to pass these 5 integers and 5 strings to a PowerShell script because Jenkins can only run a PowerShell or Python script, but I'm not entirely sure how can I achieve that. I have never used PS or done any scripting, and there isn't much on the Internet on how to even run a MATLAB script with PowerShell. (Maybe I should check batch file scripts running MATLAB scripts.)
The only option I've found so far is writing into a (temporary) file with MATLAB, then reading from it (and deleting it), it could be a .txt file, or preferably a .csv file (although using csvwrite is not recommended by Mathworks), but this isn't very reliable. Can anyone suggest other methods to pass it more directly? The MATLAB file is not a function, but it can be made to be one that has these variables as outputs. Also, it's fine if the integers are cast to another integer type.
Like #TessellatingHeckler said the way is $results = matlab.exe yourscript.
Here is an example if you want more features when launch the tests like no display windows ,run in a batch mode or wait to the end of matlab execution.
runTestMatlab (){
result=$(matlab.exe -wait -nosplash -noFigureWindows -batch TestScript.m)
if [ $? -ne 0 ]; then
# Error with the Matlab run
echo $result
return 1
fi
echo "$result"
return 0
}
Then you can parse the result with awk or any other tool that you want.

perl program to handle return of batch file

i am trying to run a batch file from a perl script but i am not able to handle the return of a batch file. below is my code
perl script:
// call a batch file
my $output =system("D:\\WORKSPACE\\CC_Triggers\\batch_file.bat");
// based on output check the status of the batch file
if($output==0){
print "success in trigger**********";
}
else
{
print "FAilure**********";
}
batch file:
set "java_output="
setlocal enableDelayedExpansion
//this will call a java program and get return value.
for /f "delims=" %%J in ('java -cp "PMDfileRead.jar;jxl.jar" PMDfileRead') do (
set "java_output=!java_output! %%J"
)
endlocal & set java_output=%java_output%
// check the ouput of java and act accordingly
IF %java_output% == 1 (
echo failed
exit(1);
)else (
echo succeeded
)
basically i am trying to validate an xls file and return flag from java code which is being called by a batch file and from ther i need to return back to perl script which i am not able to get. in case of success and failure, i am getting as "0" as output due to which output is success.. request to please correct my code or suggest me the best way to handle this.
edit: Sorry i somehow read past the comment by mpapec stating the same thing.
The Perl part is fine. If you always get a 0, it has to be the batch script acting up. Or the Java.
If you want to inspect the return value in Perl for anything except whether it is zero or not, then you would have to shift it right 8 bits.
my $output = (system("D:\\WORKSPACE\\CC_Triggers\\batch_file.bat")) >> 8;
But as you only check for zero or not, that should not be an issue here.
edit:
When using Windows, it is important to never define an environment variable ERRORLEVEL as that will mix up with the actual exit codes returned by applications. This is explained in more detail here: How do I get the application exit code from a Windows command line?
Replace your system() call with backticks instead:
A system() wrapped call returns the exit status of the command, whereas using ``'s returns the actual STDOUT (i.e. your echo statements)
For more info:
What's the difference between Perl's backticks, system, and exec?
i.e.:
my $output = `D:\WORKSPACE\CC_Triggers\batch_file.bat`;

CMD - If exists <file>

The below commands (with debug lines added - indented) should only redirect the echo's output to a file, should it already exist, according to my understanding.
However, it would seem that if exist %test0% always fills the file (creating it if non-existant) with the echo's output.
Does anyone know what is wrong?
#echo off
type test.bat
set test0="e:\documents and settings\administrator\desktop\test.log"
echo.&echo.
if exist %test0% (echo !!Exists!!) else (echo !!Doesn't Exist!!)
(if exist %test0% echo.&echo.&echo -------------------------------------------------&echo.&echo.)>>%test0%
And the file gets created(!)
EDIT: This above was a simplified example, and unfortunately MSalters answer doesn't help me solve the full command (I had hoped it would). The full one line if statement is:
if exist %test0% (echo.&echo.&echo -------------------------------------------------&echo.&echo.) else (set /p .=<nul)>>%test0%&set errorlevel=0||set errorlevel=1
How would I have whichever condition of the if matched output to the file (Hopefully with only one reference to the file, i.e., not one in each if conditional), and have the errorlevel set based on the existance of the file?
Could anyone help with the actual full command issue?
You should never set ERRORLEVEL directly. That name is reserved for reporting on the results of the prior command. When you set the value directly, you override the intended functionality and it ceases to expand to the actual ERRORLEVEL, it expands to the value you set instead. That can break all kinds of code.
You can force the ERRORLEVEL to a value by running a command with known result, redirecting output to nul if necessary: ver >nul sets ERRORLEVEL to 0, set /p .=<nul sets ERRORLEVEL to 1.
You can force the ERRORLEVEL to any particular value of your choosing by using cmd /c exit /b N, where N is an integral value.
You also have faulty logic. Your IF command succeeds (has no error) regardless whether the condition evaluates to TRUE or FALSE. If you want to set the ERRORLEVEL, then you need to do it within your parenthesized blocks.
There is nothing wrong with putting everything on one line, but I find the code easier to read when using multiple lines for complex statements like yours. I believe the following is what you are looking for.
if exist %test0% (
echo.
echo.
echo -------------------------------------------------
echo.
echo.
ver >nul
) >>%test0% else (
set /p .=<nul
)
Edit in response to comments
Not much change needed.
if exist %test0% (
(
echo.
echo.
echo -------------------------------------------------
echo.
echo.
set ERR=0
) >>%test0%
) else (
copy nul %test0%
set ERR=1
)
Check your parentheses. (x) >> output.log redirects the output of x to output.log. That means the redirection happens regardless of what the output is, and in particular always creates the file.
Now if you'd write if Y (echo Text >> output.log) the redirection would be conditional on Y, and might not happen.
[edit]
With the question as it's worded now, the simple solution seems to be:
Set %ERRORLEVEL% based on exist %test0%. No redirection has happened at this point.
Use %ERRORLEVEL% to determine what to do. You can change %test0% without altering %ERRORLEVEL%.
BTW, ERRORLEVEL is not %ERRORLEVEL%

Parse multiple arguments inside a batch file.

I would like to read two parameters that are passed to a batch file. The batch file will be executed from a C++ program using CreateProcess method. The second parameter to the batch file is a folder path, so from the program if I am passing the second parameter such as "E:\test folder\test2" the batch file does not get executed.
But if I instead pass E:\test folder\test2 the batch file gets executed but obviously the second parameter has the value E:\test only.. So what I would like to do is to read the first parameter using %1 and get the rest of the contents into another variable.
Can some one tell me how I can achieve this ? I tried with %* but it gives me both first and second parameters. I would like to remove the first token with space as delimiter so that I have the rest of the contents in the variable. Is there a way to do this ?
For example If I pass test.bat testparameter1 E:\test folder\test folder2\test folder3
I would like to read the value E:\test folder\test folder2\test folder3 into a variable.
If I pass test.bat testparameter1 E:\test\test folderX\test folderY the valueIi want to read in to a variable inside the batch file is E:\test\test folderX\test folderY
Can someone help me with this ? Thanks in advance.
Could you change spaces in the path by another character in your C++ code? For example, if we change spaces by arroba, then you could pass this:
test.bat testparameter1 E:\test#folder\test#folder2\test#folder3
and in the Batch file do the opposite change this way:
set param2=%2
set param2=%param2:#= %
Another possible method is to collect all the parameters from the second one on in the same variable, separating each one by one space:
set param1=%1
shift
set param2=
:nextParam
set param2=%param2% %1
shift
if not "%1" == "" goto nextParam
If your batch file is called with
test.bat testparam1 "E:\test\folder2\test folder 3"
You can read the parameters using %1 and %2
rem Contents of test.bat
#echo %0
#echo %1
#echo %2
The above produces:
C:\Temp>test testparam1 "E:\test\folder2\test folder 3"
test.bat
testparam1
"E:\test\folder2\test folder 3"
C:\Temp>
So you already have the parameters as variables; they're called %1 for the first one, %2 for the second, and so forth.
If the problem is that you're trying to do something using the "E:\test\folder2\test folder 3" path, just make sure you add a trailing backslash before passing it in:
"E:\test\folder2\test folder 3\"

Batch File - REN command's ErrorLevel returns 0 even on failure

This is related to my earlier question.
ren "C:\Temp\%%A" "%%A"
if errorlevel 0 (
"C:\Program Files\7-Zip\cmdline\7za.exe" a -tzip -mx9 "C:\temp\Zip\%%A.zip" "C:\temp\%%A"
Move "C:\temp\%%A" "C:\Temp\Archive"
)
In the above, the IF evaluates to true always, even if REN command fails.
The idea is to check if a file is not locked by any other application, if not then Archive it and move it elsewhere.
How best to do this?
Thank you.
Type help if on the command line to get some information on the errorlevel handling.
The problem with your code is, that the expression IF ERRORLEVEL N is evaluated to true for any number equal to or greater than N
Usually only ERRORLEVEL 0 indicates success, any other (greater) value is a sign of some error. To simply check, if nor error occurred, reverse your check to:
IF NOT ERRORLEVEL 1 (
REM your code here
)
or as an alternative, exit the script:
IF ERRORLEVEL 1 EXIT /B
you can also make a rem.bat that'll make the error level calling something like this IF ERRORLEVEL==300 call rem.bat or you can just make every error level unlockable by using a level of 0. you can varrie on things not only will it make the app run more smoothy but itll creat no lagging in the way ur fan speed will stay the same as the errorlevel will use more cpu usage.
REN is an internal command and does not set ERRORLEVEL (I'm looking for the same answer here)