4

I'd like to run several lines of code, but I'm unsure if any line will throw an error. If an error occurs however, I'd like the script to ignore that line and continue on.

One choice would be to have a try-catch-end block, that skips over a block of code that may throw errors. However, as soon as an error occurs, the rest of the code after the error in the try-statement is not executed.

TL;TR: Do I have another choice than writing a try-catch-end block for every individual line in the following example code?

Example code:

try
  disp('1st line');
  disp('2nd line');
  PRODUCE_ERROR;  %throws an error, variable/function does not exist
  disp('3rd line'); %%%%%
  disp('4th line'); % these lines I would like to keep executing
  disp('5th line'); %%%%%
catch
  disp('something unexpected happened');
end

Output:

1st line
2nd line
something unexpected happened

Output that would be preferred:

1st line
2nd line
something unexpected happened
3rd line
4th line
5th line

related: Why should I not wrap every block in "try"-"catch"?

user2305193
  • 2,079
  • 18
  • 39

2 Answers2

4

One option is to put each section of code in a function and iterate over a cell array of the function handles. Here's an example with a list of anonymous functions:

fcnList = {@() disp('1'); ...
           @() disp('2'); ...
           @() error(); ...    % Third function throws an error
           @() disp('4')};

for fcnIndex = 1:numel(fcnList)
  try
    fcnList{fcnIndex}();  % Evaluate each function
  catch
    fprintf('Error with function %d.\n', fcnIndex);  % Display when an error happens
  end
end

And here's the output this generates, showing that functions are still evaluated even after one throws an error:

1
2
Error with function 3.
4

The above example works for the case when you have individual lines of code you want to evaluate sequentially, but you can't fit multiple lines into an anonymous function. In this case, I would go with nested functions if they have to access variables in the larger workspace or local functions if they can operate independently. Here's an example with nested functions:

function fcn1
  b = a+1;     % Increments a
  fprintf('%d\n', b);
end
function fcn2
  error();     % Errors
end
function fcn3
  b = a.^2;    % Squares a
  fprintf('%d\n', b);
end

a = 2;
fcnList = {@fcn1 @fcn2 @fcn3};

for fcnIndex = 1:numel(fcnList)
  try
    fcnList{fcnIndex}();
  catch
    fprintf('Error with function %d.\n', fcnIndex);
  end
end

And the output:

3
Error with function 2.
4
gnovice
  • 125,304
  • 15
  • 256
  • 359
  • is there a quick & dirty way you would suggest to convert lines of code into a list of anonymous functions? – user2305193 Sep 14 '17 at 16:48
  • @user2305193: I added another example. Hope that helps. – gnovice Sep 14 '17 at 17:09
  • I meant more in simple terms, as in search & replace these lines of code. But I guess this is more something you would do with a simple notepad replace command (at least in Windows). The example with the multiple lines of code doesn't make sense to me, since (as far as I can see) it would take about equal amounts of code to write a try-catch-end statement around every commandline. – user2305193 Sep 14 '17 at 17:40
1

A simpler approach involves reading the script file line by line and evaluating each line in turn. This assumes that the script you want to run does not include any multi-line statements (such as e.g. a for with the end on a different line, or a statement broken onto multiple lines using ...). This is a strong limitation, as it is common to e.g. initialize a matrix using multiple lines of text.

This is the function:

function execute_script(fname)
fid = fopen(fname,'rt');
n = 0;
while ~feof(fid)
   cmd = fgetl(fid);
   n = n+1;
   if ~isempty(cmd)
      try
         evalin('caller',cmd);
      catch exception
         disp(['Error occurred executing line number ',num2str(n),': ',exception.message]);
      end
   end
end

It does exactly as I described above: it reads in a line, then uses evalin to evaluate that line in the caller's workspace. Any variable created is created in the caller's workspace. Any variable used is taken from the caller's workspace.

For example, I create the file testscript.m with the following contents:

A = 1;
B = 2+C; % This line needs a variable not defined in the script!
D = 5;

Next, at the MATLAB command prompt:

>> execute_script('testscript.m')
Error occurred executing line number 2: Undefined function or variable 'C'.
>> whos
  Name      Size            Bytes  Class         Attributes

  A         1x1                 8  double                  
  D         1x1                 8  double                  

The variable A and D were created. If I define C:

>> C=0;
>> execute_script('testscript.m')
>> whos
  Name      Size            Bytes  Class         Attributes

  A         1x1                 8  double                  
  B         1x1                 8  double                  
  C         1x1                 8  double                  
  D         1x1                 8  double                  

With a variable C defined, the script runs without error, and defines B also.

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120