How to make matlab block the shell in windows? - matlab

I use win7 and matlab2012a. I want to write a shell script to test my matlab scripts with different parameters. I use cygwin for this task. For example, alpha is the parameter and the matlab script is getall.m. The matlab script will read parameters from txt file 'param.txt'.
#!/bin/sh
# List=`seq 0.1 0.01 1`
List=`seq 0.1 0.1 0.2`
for alpha in $List
do
echo -ne "20\n61\n80\n1\n0.3\n${alpha}" > param.txt
matlab -nodesktop -r "getall;quit;" #time consuming
done
My problem is that script "getall.m" is time consuming, so I'd like to exec it one at a time. But I found that matlab command returns immediately. So the upper script will start a lot of matlab instances at the same time. I also tried the matlab command in cmd, but nothing changes. In ubuntu, matlab blocks the shell by default.
My question is how to make the matlab command to block the shell in windows?

There's a matlab -wait command line switch on Windows that will make it block.
http://www.mathworks.com/help/matlab/ref/matlabwindows.html

I don't know the "right" way to do this - but I do have a hack for you:
Make the matlab script create a file called "matlabDone" in the /tmp directory just before quitting; your shell script can go around a loop looking for this file. Once it exists, you know matlab is finished. Delete the file, and go around the loop again. Something like this:
List=`seq 0.1 0.1 0.2`
for alpha in $List
do
echo -ne "20\n61\n80\n1\n0.3\n${alpha}" > param.txt
matlab -nodesktop -r "getall;quit;" #time consuming
while [ ! -e /tmp/matlabDone ]
do
sleep 1
done
rm /tmp/matlabDone
done
Then make the last line of your matlab script create the file /tmp/matlabDone...
As I said - it's a hack...
PS I am not 100% sure what functions are available in cygwin. If you can't use sleep, I saw an interesting post suggesting that ping -n 2 127.0.0.1 > /dev/null (or equivalent ... depending on the version of ping you might need -c 2 -i 1 to get "one second per ping, count two") can be an alternative to sleep().

Related

How to run for loop in batch file step by step

I am trying to call MATLAB from the batch file several times. In this way, I used for loop to execute my MATLAB scripts several times. But what I got after running my batch file is to run all MATLAB files simultaneously. What I want is that, firstly, it runs once MATLAB, and when it is finished, it starts to run for the next time. Here is my code. Any help will be appreciated!
#echo off
for /l %%x in (1, 1, 2) do matlab -r "cd('H:\EngFiles\Ali\Backups codes\New set with multiple scenarios_Parallel');Bi_Objective_algorithm; exit"
pause
This page in the documentation describes how to call MATLAB from a Windows batch script: https://www.mathworks.com/help/matlab/ref/matlabwindows.html
The -wait option tells the matlab command to not return until MATLAB exits. For example:
matlab -wait -r "disp(1); exit"
However, since R2019a the -r switch is no longer recommended. That is the release where they introduced the much better -batch option:
matlab -batch "disp(1)"
Note that it is no longer necessary to include exit in the command.

Run multiple MATLAB instances concurrently through a batch file

Is there a way to run multiple .m files in different instances of MATLAB concurrently through a batch file? The task that I want to accomplish is like below:
Open x instances of MATLAB;
Let different instances run different .m files simultaneously (so that my CPU power could be completely utilized);
When all instances finish, exit all MATLAB.
Could a single batch file accomplish this process? The reason I want to use a single batch file to do so is that I want to call this batch file in my MATLAB script. Essentially, I want to do parallel computation. (Since some of my scripts have to be run with MATLAB 2007, which doesn't have the parallel computing toolbox, I have to find a way around.)
Please explain the syntax of your code since I know little about the command prompt.
Currently, I only know how to do the task in sequence, just like the code shown below.
cd "C:\My_MATLAB_folder_path"
matlab r- "mfile01;exit"
matlab r- "mfile02;exit"
...
matlab r- "mfilexx;exit"
If a command prompt could not achieve this process, what alternative methods could I use? One important thing is that whatever method may be used, it must be able to be called in a MATLAB script.
When CMD executes a command or program from a batch file it waits for the launched program to exit, then executes the next command. To overcome this, you can prefix each invocation of MATLAB with start command: start "" matlab r- "mfilexx;exit"
Also making a slight delay between MATLAB invocations might be a good idea to prevent putting hard disk under excessive stress.
So the task could be done with something like this:
#echo off
setlocal
REM Delay is in seconds after /t switch
set "delay=timeout /t 1 /nobreak >nul"
REM Or this for Windows XP: (Delay is in milliseconds after -w switch)
set "delay=ping -n 1 -w 1000 127.255.255.255 >nul"
cd /d "C:\My_MATLAB_folder_path"
start "" matlab -r "this.m;exit"
%delay%
start "" matlab -r "that.m;exit"
%delay%
...
Or Alternatively it can simplified by witting the batch script this way:
cd /d "C:\My_MATLAB_folder_path"
for %%A in (
"this.m"
"that.m"
"other.m"
"add each file in a new line or on the same line separated with space.m" "one another.m"
) do (
start "" matlab -r "%%~A;exit"
%delay%
)

Force Matlab output to command line

I am running a MATLAB script from the Windows command prompt:
"C:\Program Files\MATLAB\R2014B\bin\matlab" -nodisplay -nosplash -nodesktop -wait -r "test.m"
The test.m is simple:
function test
disp('Hello!');
The output is displayed in the Matlab Command Window. Is there any way how I can force output to the windows prompt?
Use the command line option -log when you call Matlab from the command line (or any other shell or batch (e.g. cmd or bat) script).
It isn't documented as of Matlab 2017b, but it works.
Side note: -nodisplay isn't supported in the Windows version of Matlab, but if you want to prevent it from displaying figures, use -noFigureWindows instead.
Since R2019b, there is a new command line option, -batch, which redirects the output to the command line and handles other stuff for batch processing. See the documentation for Windows.
matlab -batch "statement to run"
This starts MATLAB without the desktop or splash screen, logs all output to stdout and stderr, exits automatically when the statement completes, and provides an exit code reporting success or error.
I don't know of a way to do it in Windows to get Matlab to actually run in the DOS window which is what you would need for the display to be written in it. (FYI: You can in LINUX - but I assume you need to run in Windows).
For running in Matlab you have 2 alternatives that I can think of:
-logfile FILE on launch which will record all output to a FILE you specify - however how and when the file is written to disk is controlled by Matlab and I haven't tested to see - if your code doesn't do much it might only be written on Matlab exit.
diary FILE in your Matlab command, i.e. -r "diary FILE.TXT; test.m; diary OFF" - this is similar to above - but uses the diary function.
However you can get what you want if you can run your code compiled (I know thats a big if as you may not have the compiler - or if you regularly want to update test.m this is not the most efficient...
When you run a compiled code from a DOS prompt all the terminal messages are written to the DOS prompt. One thing I'd advise if this is suitable is to delete the "splash.png" file from your installation directory to avoid the splash screen displaying when you run from the DOS as its (probably) not needed.
I have found a solution at:
https://www.mathworks.com/matlabcentral/answers/91607-how-can-i-redirect-the-command-window-output-to-stdout-and-stderr-when-running-matlab-7-8-r2009a-i#answer_100958
I will replicate it here for convenience.
First I need to modify the matlab script to output to a text file:
function test
fid=fopen('output.txt','w');
fprintf(fid,'Hello!');
fclose(fid);
Then I should run the Matlab using a bat file with one additional command to display the contents of the output.txt:
"C:\Program Files\MATLAB\R2014B\bin\matlab" -nodisplay -nosplash -nodesktop -wait -r "test.m"
type output.txt
The type command will display the contents of 'output.txt' in the command window. So answer from #matlabgui was almost there. Thank you.
It is not a very elegant solution, but it works.

How : MATLAB script that can get arguments from Unix command-line

Just for the sake of concreteness, consider the following super-simple Python script, in a file called add_em:
#!/usr/bin/env python
# script name: add_em
from sys import argv
x = int(argv[1])
y = int(argv[2])
x_plus_y = x + y
print '%d' % x_plus_y
I can now run this script, and pass arguments to it, from the Unix command line, like this:
% python add_em 3 8
11
If I make the script executable, I don't even need to mention python on the command line:
% chmod +x add_em
% add_em 41 -29
12
Can someone show me how to write (and run) a MATLAB script so that it performs exactly like the script above does? In particular, it must be able to read its arguments from the Unix command line (as opposed to, e.g., the MATLAB GUI's "command line"), and print their numerical sum to standard output.
NOTE: this script need not be "stand-alone"; IOW, one may assume that MATLAB is locally installed, and even that one can mention matlab in the command line (analogously to the first form above, where the python interpreter is explicitly invoked on the command line).
Thanks!
PS: Needless to say, this script is the antithesis of "robust", but my aim was to produce a readily conveyed example.
You can have a MATLAB function doing what you want inside add_em.m
function add_em(x, y)
x_plus_y = x + y;
disp(x_plus_y);
exit;
and then call it from Unix command line using the -r switch. Example:
matlab -nodesktop -nojvm -nosplash -r "add_em(3, 8)"
The - options suppress desktop, java and splash so the script/function will be executed without additional overhead.
You can additionally suppress the MATLAB welcome/copyright message by redirecting output to a logfile (for any computations) or tailing, for example, the output in order to get something printed on terminal
matlab -nosplash -nodesktop -nojvm -r "add_em(3, 8)" | tail -n 3
Update: Just found out this post/answers with relevant info: suppress start message of Matlab

Writing log statements to standard output with Matlab

We're starting Matlab from our Jenkins buildserver. As the build may take some time it would be nice to get some log-outputs while matlab is running. Is there a way to print text to standard output? disp, fprintf and java.lang.System.out.printline only write to the matlab console, not to standard output.
Using a logfile or a pipe won't help, as Jenkins only reads from standard-output during a build step.
How can we write log-statements to the standard output while matlab is running?
EDIT:
We're running Matlab 2010b on Windows
Depending what you are doing with Matlab you could probably launch it in command line without GUI. I used this on a server and it behaves pretty much like a shell script and writes to standards outputs.
See the startup options.
I used the following:
/path/to/matlab -nojvm -nodisplay -nosplash -nodesktop -r /path/to/mfile
EDIT: forgot to mention one very important little detail, place an exit command at the end of your mfile or Matlab will hang there waiting.
It seems that the combination of -wait and -log (not -logfile) clones the command window output to the parent console's stdout, but only if you call the MATLAB executable in [MATLABROOT]\bin, not [MATLABROOT]\bin\win64 (the subdirectory for current arch).
Tested on Windows with R2015b and R2016b:
C:\MATLAB\bin\matlab.exe -wait -log
NOT
C:\MATLAB\win64\bin\matlab.exe -wait -log
Remember to put an exit/quit in your script if you are running with -r.
The only trouble is that I can't seem to find any documentation for the -log option! Meh.
There don't seem to be any good ways to do this from within MATLAB. The easiest way I can think of doing this is by using a shell script. You could write a small shell script which would simply print any input to stdout, and then call that shell script from within matlab using the unix (or system) commands. Jenkins should be able to read the command-line output of the script and work with that.
I figured out a way to do this and am also doing it for Jenkins Matlab interface on windows.
Basic idea is that you will use diary command, but then tail -f the file, but you need a smart way to kill the tail command if you open multiple matlab instances because there will be name collisions. So the method I'm using is to name the file log.txt where the PID used is MATLAB's PID it is using when it opens.
There is an undocumented feature in MATLAB that allows you to get its PID. So now, both your batch file and MATLAB know the PID without having to read/write to a random text file that will get messy when executing multiple jobs. So the PID you use that as your unique identifier. The PID of "tail -f" is also used by MATLAB to kill tail -f to make the batch file die and is found by MATLAB using the commandline details associated with the process invocation since it uses again the unique PID log file name.
This uses some wmic commands and needs Windows Vista/7 or above. With XP you probably have to work harder to get the process ID's but should be still possible.
Here is what to do:
1) Get gnu awk for windows: http://gnuwin32.sourceforge.net/packages/gawk.htm
2) Get tail.exe from windows resource kit: http://www.microsoft.com/en-us/download/details.aspx?id=17657
3) Make sure tail and awk are in your path (the windows resourece kit I don't think automatically puts them in the path)
3) Create a batch file called matlabrun.bat as follows, (note: you need the #echo off, also the entire command is quite long, scroll right..)
#echo off
wmic process call create "c:\matlab\bin\win64\matlab.exe -r \"cd('c:\jenkins\workspace\test'); workdir=pwd; outpath=[pwd '\output'] ; try; run('C:\MATLAB\work\test_run'); end; quit; \" " | findstr ProcessId | awk "{print $3}" | awk -F";" "{ print $1 }"
4) Create another batch file called run.bat with:
for /f %%i in ('matlabrun.bat') do (
echo MATLAB Log... > log%%i.txt
tail -f log%%i.txt
set logfilename=log%%i.txt
goto next
)
:next
del /f %logfilename%
5) The run.bat file will execute matlabrun.bat and since -wait is not passed, matlab will immediately return to the command line and execute the tail -f command. That will block the batch file from completing until you kill it. matlabrun.bat returns the PID of matlab.
6) Another important note: since you are using "wmic process create" which will provide you with a PID that MATLAB is using, but will default to a working directory of c:\windows\system32. So that is why I pass the work directory to matlab. wmic process create is also a bit particular about what parameters you put into your command string for matlab to run. So it appears to have a problem with using commas in your command string. So I suggest not to use those, or figure out how to escape them (it might be that ^, works, but I just removed my commas anyway in my matlab run command).
6) The "test_run.m" file contains the following code to write to the correct log file and to kill correct tail -f instance.
matlabpid=feature('getpid');
filename=['log',num2str(matlabpid),'.txt'];
filenamefull=[workdir,'\',filename];
diary(filenamefull);
disp('Script starting...')
%%% put your code here %%%
disp('Script completed...');
diary off;
%%% FIND PID of tail.exe and kill it
%%% by using the name of the log file in the process command line
[a,b]=dos(['wmic process get Commandline,ProcessId']);
C=textscan(b,'%s','delimiter','\n');C=C{1};
for jj=1:size(C,1),
if strfind(C{jj},filename),
D=textscan(C{jj},'%s');D=D{1};
dos(['taskkill /f /pid ',D{4}]) %kills tail.exe which is the log watcher
break
end
end
7) You start it by doing run.bat. It will go and execute matlab, then start tailing the output while MATLAB runs in real-time. Then when done it will delete the log file.
8) My directory structure / files are in these locations (I'm using win7 64bit):
c:\jenkins\workspace\test\tail.exe
c:\jenkins\workspace\test\awk.exe
c:\jenkins\workspace\test\matlabrun.bat
c:\jenkins\workspace\test\run.bat
c:\matlab\work\test_run.m
c:\matlab\bin\win64\matlab.exe
If you are using 32bit matlab, point it to the win32 directory. To get the correct PID, you need to specify the actualy matlab.exe binary in the win32 or win64 directory.
You can do this by pointing the -logfile option to the Jenkins log file. Something like the following:
"C:\path\to\matlab.exe" "-r" "functionToRun" "-logfile" "%JENKINS_HOME%\jobs\%JOB_NAME%\builds\%BUILD_NUMBER%\log" /wait
You can use the diary mode. Not sure if it will fit your specific implementation.
http://www.mathworks.com/help/techdoc/ref/diary.html
I didn't find a real solution. Mathworks created some wrapper tool. But this will only output the results after matlab has exited. You won't get any ouput during execution.
http://www.mathworks.de/support/solutions/en/data/1-ACT3YN/index.html?product=ML&solution=1-ACT3YN
So I'll have live without real live-output...
Or try using '-logfile' option in matlab.
matlab.exe -nodisplay -nosplash -nodesktop -wait -logfile logfile.txt -r "try script.m ;catch err; disp(err.message); end ; exit"
I prefer using bash (Execute shell) in Jenkins, then you can tail the log-file while matlab is running.
matlab.exe <...> &
matpid=$!
tail -f logfile.txt &
tailpid=$!
wait $matpid
matexit=$?
kill $tailpid
sleep 1 # Just to make sure kill is done before Jenkins step ends and no zombie processes
exit $matexit