Print Line Number in Matlab - matlab

I have a Matlab function which runs into few thousands of lines of code. Under certain condition, it is breaking. I can as well, debug the code and run step-by-step.
So, I have try, catch block in Matlab to handle the error. In addition to this, is it possible to capture, the line number of the code as well.
For Example :
try
Error here <-----
catch err
disp(['Error occured on line No ' num2str(lineNo])
end
Any idea, how it can be implemented ?

Try this. This will print out the line numbers along with the full stack.
try
%some code;
catch exc
getReport(exc, 'extended')
end

You may also consider using
>> dbstop if error
before running the code: this way when an error occurs, Matlab creates a debug breakpoint and allow you to debug at the error.

You can try in this way:
try
Error here <--------------
catch err
disp([err.identifier]);
disp([err.message]);
for e=1:length(err.stack)
disp(['Error in ' err.stack(e).file ' at line ' num2str(err.stack(e).line)]);
end
end

To print the line number you can use this command:
printf(['Line number ' num2str(dbstack.line) '\n'])

Related

Can script be configured to "exit on unhandled exception"?

Is there a simple way to configure a MATLAB script so that it exits upon encountering an unhandled exception (as opposed to reverting to the REPL)?
The reason for this is that when executing many runs of a script in (unsupervised) batch mode, any script that fails should exit immediately, and not hang indifinitely at (unattended) interactive prompt.
IMPORTANT CLARIFICATION: this script is meant to be executed from the Unix command line, not from the MATLAB interactive prompt. More specifically, the script is to be invoked with
matlab -nodesktop -nosplash -nojvm -r myscript.m
The script should always terminate MATLAB after it has executed all its code, and return a status code reflecting its success (0) or failure (some non-zero integer).
I'm looking for a global setting (or a command-line flag) that can be put into effect without affecting the rest of the code.
IOW, I'm looking for something analogous to the -e flag available in some Unix shells (e.g. bash, zsh), which has the effect of aborting a script immediately whenever the return status of a statement is non-zero (meaning that the statement failed).
I know that I can wrap the entire body of a script with a try-catch, like this (for example):
try
exit_code = 0;
%
% BODY OF SCRIPT
%
catch exc
fprintf(2, 'CAUGHT EXCEPTION:\n');
fprintf(2, '%s(%d): %s\n', exc.stack.file, exc.stack.line, exc.message);
exit_code = 1;
end
exit(exit_code);
...but, as I said above, I'm looking for something simple, with no, or at most minimal, impact on the code.
The default behavior when an unhandled exception occurs is that information about the error will be printed to the command window and control will return to the command window. You should not be getting an interactive prompt from the error unless you've explicitly enabled it with dbstop if error or there is a try/catch with a keyboard command in the catch block. To just get a plain error rather than an interactive prompt you can use dbclear if error to disable this behavior. I would check your startup files to make sure that you don't have dbstop if error in there.
A try/catch pair is really the only way that this can be done. What you can do is wrap your calls to your script with another file and put the call to your script within a try/catch block. This has the added benefit that you don't have to modify the script itself, just the "runner".
Also you won't want to use exit as that completely exits MATLAB.
your_script.m
disp('Doing my thing')
error('Throwing an error!')
calling_script.m
for k = 1:100
try
% Call your other script and hope for no errors!
your_script
catch ME
% Print information about the error and continue
fprintf(2, 'CAUGHT EXCEPTION:\n');
fprintf(2, '%s(%d): %s\n', ME.stack.file, ME.stack.line, ME.message);
end
end
Update
Based upon the clarification that you've provided that you want to run this from the Unix command line, you'll still want to use something similar with a try/catch statement combined with exit. Again, you could do this in an external file as shown above
calling_script.m
code = 0;
try
your_script
catch ME
fprintf(2, 'CAUGHT EXCEPTION:\n');
fprintf(2, '%s(%d): %s\n', ME.stack.file, ME.stack.line, ME.message);
code = 1;
end
exit(code)

How to catch syntax errors?

If I run the following foo.m file with run('foo.m'):
try
disp(r3)
catch ME
disp('Exception handling.')
end
I correctly get:
Exception handling.
However if I replace disp(r3) by disp('foo' 1) then I get:
Error: File: C:\Users\Pedro\Desktop\foo.m Line: 23 Column: 16
Unexpected MATLAB expression.
Error in run (line 96)
evalin('caller', [script ';']);
Why am I not catching this error with catch ME? How can I catch it?
Having a syntax error in your file, not a single line of code is broken, the full file is broken because it can not be parsed. Matlab will refuse to "understand" any code you write in your foo.m, including your try/catch. You have to write your try/catch into another function which calls the foo.m
try
foo()
catch ME
disp('Exception handling.')
end
As the matlab interpreter will highlight all syntax errors to you without running the code, you typically don't need to check for syntax errors on runtime.

Control flow within an eval function in Matlab

If I include a continue as a parameter of an eval() instruction, it does not work as expected. For example, when executing the following code:
listParam = {'a','b','c'};
a = 17;
b = NaN;
c = 4;
for ii=1:numel(listParam),
eval(['if isnan(',listParam{ii},'), continue; end']);
disp(['The parameter ', listParam{ii}, ' is not a NaN.']);
end
It will prompt the error:
Error: A CONTINUE may only be used within a FOR or WHILE loop.
Anybody knows why?
Note: I know that I should avoid eval() and the previous example could be refactored in a much better coding; but I found a weird behaviour and I am curious what is happening.
The expression you pass to eval must be a valid matlab expression on it's own, any surrounding code is not considered. This means each continue must be surrounded by a loop. Either put the surrounding for within your eval or put the continue outside.
As #Daniel has pointed out, eval is called by the script, while it is not directly controlled by the for loop. You can think it as: the continue in eval would move the program counter to the head of the code inside eval, but not that of the for loop; this of course would fail, as Matlab does not allow jumping between lines.
A continue can only appear directly inside a for or while loop. However, you can hack the code like this:
for ii=1:numel(listParam),
eval(['if isnan(',listParam{ii},'), x=1; else, x=0; end']);
if x
continue;
end
disp(['The parameter ', listParam{ii}, ' is not a NaN.']);
end
Strangely, x happens to appear in the script's stack. However, this is far from a good piece of code. Never use this method.
Edit: about the "control" scope of eval.
I'm not talking about the variable scope / workspace of eval. Hints can be found in several documentations like this and this. In short, eval uses the "current" workspace.
However, I found the following things interesting:
Running continue directly in eval
for ii = 1:2
eval('continue')
ii+10
end
This simply fails, as shown in the question. The error is Error: A CONTINUE may only be used within a FOR or WHILE loop. which means the continue inside eval cannot find any loop (the for loop).
Calling a separate script in a for loop
for ii = 1:2
foo
ii+10
end
while script foo.m is
ii
continue
First of all, in foo.m Mlint gives a red-line warning, which usually indicates an error that can stop the code from running, saying that CONTINUE is only valid in a FOR or WHILE loop. But pressing F5 on foo.m does not have any problem - in fact running a single continue anywhere does not crash the code.
Running the main script gives output
ii =
1
ii =
2
>>
....so foo.m catches the for loop?
eval('foo') - I really don't understand Matlab
for ii = 1:2
eval('foo')
ii+10
end
The result surprised me a bit.
ii =
1
ans =
11
ii =
2
ans =
12
>>
Thought: eval runs the code in an independent control flow, but shares its workspace with the current one. It is (something but not exactly) like an isolated world model, in which (here in Matlab) different pieces of code can interact with the same set of variables, but cannot interact with each other in the sense of control flow.
Unfortunately, I was unable to find any existing resources as reference to prove this idea.
This does not change my solution: in any case, try to avoid using eval.

Running a matlab program with arguments

I have a matlab file that takes in a file. I would like to run that program in the matlab shell, such as prog. I need to implement it so that it takes a number of arguments, such as "prog filename.txt 1 2 which would mean that i can use filename.txt and 1 2 as variables in my program.
Thank you!
In order to make a script accept arguments from the command line, you must first turn it into a function that will get the arguments you want, i.e if your script is named prog.m, put as the first line
function []=prog(arg1, arg2)
and add an end at the end (assuming that the file has only one function). It's very important that you call the function the same name as the file.
The next thing is that you need to make sure that the script file is located at the same place from where you call the script, or it's located at the Matlab working path, otherwise it'll not be able to recognize your script.
Finally, to execute the script you use
matlab -r "prog arg1 arg2"
which is equivalent to calling
prog(arg1,arg2)
from inside Matlab.
*- tested in Windows and Linux environments
Once your function is written in a separate file, as discussed by the other answer you can call it with a slightly more complicated setup to make it easier to catch errors etc.
There is useful advice in this thread about ensuring that Matlab doesn't launch the graphical interface and quits after finishing the script, and reports the error nicely if there is one.
For example:
matlab -nodisplay -nosplash -r "try, prog(1, 'file.txt'), catch me, fprintf('%s / %s\n',me.identifier,me.message), exit(1), end, exit(0)"
The script given to Matlab would read as follows if line spaces were added:
% Try running the script
try
prog(1, 'file.txt')
catch me
% On error, print error message and exit with failure
fprintf('%s / %s\n',me.identifier,me.message)
exit(1)
end
% Else, exit with success
exit(0)

How to exit a matlab m-file (NOT the matlab itself) if the user enters bad inputs?

How to exit a matlab m-file (NOT the matlab itself) if the user enters bad inputs?
I know if a m-file goes wrong at run time we can press Ctrl-C to stop it. but I need a command to put it in my m-file to do so if something bad happens.
Please don't suggest 'exit' or 'quit' commands as they terminate the entire matlab and I don't want it.
I am not sure how you define "exit", but error seems to be the function you need.
y = input('Please input a non-negative number: ');
if(y<0)
error('input must be non-negative');
end
disp( sprintf('y=%f', y ) );
Hey I suppose you could use a try-catch combination to handle a somewhat unexpected error and do something about it.
As an example,
function [ output ] = test(input)
Bmat = [ 1 1 1 ] % Some matrix
try
input*B;
catch ME
disp(ME.message)
return; % This is the statement that exits your function
end
end
If you run
>> test([1 1 1])
It won't work since the variables 'input' and 'B' have mismatched inner dimensions, but the 'try' statement will throw an exception to 'catch', and do whatever you want from there. In this case, it will display an error message at the command line and exit the function.
The variable 'ME' here is just a MATLAB object for error handling, and ME.message stores a string containing the type of error the interpreter caught.
I just read your question again... I assume the command 'return' is probably what you are really after, you will be able use it to exit from any logic or loop statements, as well as functions.
You can read more about the 'return' command and error handling from the MATLAB documentation,
http://www.mathworks.com/access/helpdesk/help/techdoc/ref/return.html
You can just put a error command like error('bad user input') and it should stop the script.
Edit: alternatively, you could just refactor your code to not run unless you set the input flag to be true. Something like
inp = input('>', s)
if validateInput(inp)
%do you stuff here or call your main function
else
fprintf('Invalid input')
end