This is probably too easy, but I cannot google the answer for this: how can I get command line arguments in matlab script.
I run matlab as matlab -nodisplay -r "run('script.m')" and I want to return all arguments as a list. Something similar to python sys.argv. How can I do this?
I'm using Linux Mint and MATLAB 2015a.
I came up with a simple function that works on both Windows and Linux (Ubuntu):
function args = GetCommandLineArgs()
if isunix
fid = fopen(['/proc/' num2str(feature('getpid')) '/cmdline'], 'r');
args = textscan(fid, '%s', 'Delimiter', char(0));
fclose(fid);
else
kernel32WasAlreadyLoaded = libisloaded('kernel32');
if ~kernel32WasAlreadyLoaded
temporaryHeaderName = [gettempfolder '\GetCommandLineA.h'];
dlmwrite(temporaryHeaderName, 'char* __stdcall GetCommandLineA(void);', '');
loadlibrary('kernel32', temporaryHeaderName);
delete(temporaryHeaderName);
end
args = textscan(calllib('kernel32', 'GetCommandLineA'), '%q');
if ~kernel32WasAlreadyLoaded
unloadlibrary kernel32;
end
end
args = args{1};
On your sample call, it would return this:
>> GetCommandLineArgs
args =
'/[path-to-matlab-home-folder]/'
'-nodisplay'
'-r'
'run('script.m')'
It returns a cell array of strings, where the first string is the path to MATLAB home folder (on Linux) or the full path to MATLAB executable (on Windows) and the others are the program arguments (if any).
How it works:
On Linux: the function gets the current Matlab process ID using the feature function (be aware it's an undocumented feature). And reads the /proc/[PID]/cmdline file, which on Linux gives the command line arguments of any process. The values are separated by the null character \0, hence the textscan with delimiter = char(0).
On Windows: the function calls GetCommandLineA, which returns the command line arguments on a string. Then it uses textscan to split the arguments on individual strings. The GetCommandLineA function is called using MATLAB's calllib. It requires a header file. Since we only want to use one function, it creates the header file on the fly on the temporary folder and deletes it after it's no longer needed. Also the function takes care not to unload the library in case it was already loaded (for example, if the calling script already loads it for some other purpose).
I am not aware of a direction solution (like an inbuilt function).
However, you can use one of the following workarounds:
1. method
This only works in Linux:
Create a file pid_wrapper.m with the following contents:
function [] = pid_wrapper( parent_pid )
[~, matlab_pid] = system(['pgrep -P' num2str(parent_pid)]);
matlab_pid = strtrim(matlab_pid);
[~, matlab_args] = system(['ps -h -ocommand ' num2str(matlab_pid)]);
matlab_args = strsplit(strtrim(matlab_args));
disp(matlab_args);
% call your script with the extracted arguments in matlab_args
% ...
end
Invoke MATLAB like this:
matlab -nodisplay -r "pid_wrapper($$)"
This will pass the process id of MATLAB's parent process (i.e. the shell which launches MATLAB) to wrapper. This can then be used to find out the child MATLAB process and its command line arguments which you then can access in matlab_args.
2. method
This method is OS independent and does not really find out the command line arguments, but since your goal is to pass additional parameters to a script, it might work for you.
Create a file vararg_wrapper.m with the following contents:
function [] = wrapper( varargin )
% all parameters can be accessed in varargin
for i=1:nargin
disp(varargin{i});
end
% call your script with the supplied parameters
% ...
end
Invoke MATLAB like this:
matlab -nodisplay -r "vararg_wrapper('first_param', 'second_param')"
This will pass {'first_param', 'second_param'} to vararg_wrapper which you can then forward to your script.
Related
I am writing a script to access a function that has been written in another script.
When I run the second script the error is that the function is undefined.
I have been working backwards and am currently trying to get the function to work in the command window.
The function file has appeared in the current folder window. When it is highlighted all functions and parameters are displayed in the window below (displays the file name on top then the file contents).
I am still getting a function is undefined when I copy and paste the functions call from the script into the command window.
I tried rebuilding the functions individually in separate scripts, but I am still receiving an error message.
I have made sure the are in the same folder, and are spelled exactly the same, what am I doing wrong?
'''
%file name Lab_5_functions.m
function[vel] = velocity (g,m,co_d,t)
vel= ((g*m)/co_d)^(1/2)*tanh(((g*co_d)/m)^(1/2)*t);
end
function [dvel]= dvelocity (g,m,co_d,t)
dvel=(((.5*(g*m)/co_d)^(1/2)*tanh(((g*co_d)/m).^(1/2)*t_sec))-(((g*t)/(2*m))*(sech(((g*co_d)./m).^(1/2)*t))));
end
'''
v=velocity(1,2,3,4)
%error message below:
Undefined function or variable 'velocity'.
'''
Thanks
-MK
Matlab is searching for functions using filenames. So you define a single public function myfunc in a file myfunc.m.
You can define additional functions in that file, but they will not be accessible outside that .m file.
MATLAB looks for filenames to find the functions and expects the first line of that file to be a function definition.
For example: myfunc.m
function output = myfunc(input)
If you do want many functions in one file (like a module/library), I have used a work-around before: write all your functions in the file, then include an if-else block to call the correct function. Multiple arguments can be parsed with some simple checks (see nargin function). It is a less elegant solution; I only use it if I have many simple functions and it would be plain annoying to have heaps of .m files.
Here is a simple example:
Call the file: myfunc.m
function output = myfunc(fn, arg1, arg2, ...)
function out = func1(arg1, arg2, ...)
out = 0
if strcmp(fn, 'func1')
if nargin == 2
output = func1(arg1)
end
elseif strcmp(fn, 'func2')
...
end
This is a simple Matlab code that I'm trying to execute.
function result = scale(img, value)
result = value .* img;
end
dolphin = imread('dolphin.png')
imshow(scale(dolphin, 1.5));
The error says:
Error: File: scale.m Line: 5 Column: 1
This statement is not inside any function.
(It follows the END that terminates the definition of the function "scale".)
What am I doing wrong here?
scale.m is a function M-file because it begins with the keyword function. The part up to end is the definition of the function. When you call scale at the MATLAB command line, it executes the code in the function. The stuff that comes after end is not part of the function, and hence cannot be executed.
If you intended to write a script with a private function scale that you want to use only within this script, then put the lines of code that read and display dolphin at the top of the file. The private functions should come after the script part. This syntax is supported since MATLAB R2016b.
Otherwise, move the dolphin code to a different M-file, which would be a simple script M-file without any function definitions. This script can then use scale, which would call the function in the file scale.m.
A third alternative, keeping all code in the same file, is to not use a script at all, and put the script code inside a function:
function f % just a random name
dolphin = imread('dolphin.png')
imshow(scale(dolphin, 1.5));
end
function result = scale(img, value)
result = value .* img;
end
(The function name doesn't need to match the file name, although the MATLAB editor will warn you if these names don't match.)
Is there a similar concept to Unix 'alias' within Matlab?
This question Is there a way to do command aliasing in matlab R2011b? suggests defining anonymous functions, and extending the answer these could be sourced at startup, but this results in the function handles appearing in the Workspace, which will disappear when cleared.
Is there a more robust and Unix analogous solution? Seems like a pretty useful thing to be able to do...
I am not sure why you would want to do this, but...
Assuming you are willing to have a directory on the path dedicated to aliases you can create m files in that directory to run the aliases. In this case the aliases will not exist in the workspace. You could of course just write the alias files your self, but the following function will create aliases for you automatically. The function can get confused if the function/script you are trying to alias is not currently on the search path. The function is not "perfect" in the sense that you do not write
alias myAlias = run('full/path/to/some/script')
but rather
alias myAlias full/path/to/some/script
function alias(aliasName, functionName)
% alias myfoo foo
aliasPath = './alias';
isscript = false;
try
nargin(functionName);
catch %#ok<CTCH>
isscript = true;
end
if isscript
fileID = fopen([aliasPath, aliasName, '.m'],'w');
fprintf(fileID, '%s\n', ['run(', functionName, ')']);
fclose(fileID);
else
fileID = fopen([aliasPath, aliasName, '.m'],'w');
fprintf(fileID, '%s\n', ['function varargout = ', aliasName, '(varargin)']);
fprintf(fileID, '\t%s\n', ['varargout{1:nargout} = ', functionName, '(varargin{:});']);
fprintf(fileID, '%s\n', 'end');
fclose(fileID);
end
end
Yes there is a way. It's called a function. You just write a function to do whatever you want the alias to do. For example:
function cdhome
cd(getenv('MATLABUSERPATH'))
Then just type cdhome at the command line, exactly like an alias in a unix shell. Note that MATLABUSERPATH is an environment variable I define in startup.m. It can be easier, just save a script called cdhome.m with the following content:
cd(getenv(<ENVIRONMENT_VARIABLE_THAT_DEFINES_MY_FAVORITE_PATH>))
Or how about:
clc; clear; close all;
Save that in a script file called clean.m and then simply put clean at the top of your scripts instead of clc; clear; close all;
No, it doesn't exactly follow the unix idea of having a bunch of alias's in a single configuration file that executes on startup.
But you can do that too. Put all your aliases in a switch block, in one function, call it alias:
function alias(thecalledalias)
switch thecalledalias
case somealias
% ... define some alias
case someotheralias
% ... define some other alias
end
For autocomplete, which you would get with your shell, put a functionSignatures.json file in the same folder as the alias.m function file and populate it with your aliases:
{
"_schemaVersion": "1.0.0",
"alias":
{
"inputs":
[
{"name":"thecalledalias", "kind":"required",
"type":["char", "choices={'somealias','someotheralias'}"]}
]
}
}
Then you will get autocomplete when you type alias(...) at the command line.
But to me it is easier to have one folder, call it myaliases with one script or function for each alias, and you get autocomplete at the command line just like when you call any function (i.e., no need to type alias(<somealias>)).
I have a matlab function and I was able to run it from command line. Now I want to pass a parameter to the file from command line. The parameter is a integer. It seems when I pass from command line, it is always taken as a "char".
Here is how I run the command
matlab -nodesktop -nosplash -r "mycommand 3"
For example, if I have a function as
function [ ] = mycommand( a )
a = a+3;
disp(a)
end
it prints 54 instead of 6.
Is there a way to work around this? I don't want to check the type of the variable in my code.
Thanks
You need to execute the function as you would in the matlab interpreter:
matlab -nodesktop -nosplash -r "mycommand(3)"
(Notice the parenthesis around the 3)
MarkD gave a good answer. Although you mentioned you might be unhappy doing this (I'm sure for good reasons), another option would be to put a little extra code in to the beginning of your function, which would convert character inputs to numerical if the command were called via matlab -r:
if ischar(a)
a = str2num(a);
end
Say that, on a MATLAB interactive session, I call a function from a third party library output = long_execution(input). This function prints information via disp statements to the command window. I would like to capture the output of such disp statements on a text string that I can manipulate in MATLAB.
Is there a (hopefully easy) way of redirecting the output of disp to a text string? If so, how would you do it? (maybe via the overlading of disp?)
You can use evalc function to capture disp outputs. For example,
[T, output] = evalc('long_execution(input)');
Anything that would normally go to command window is captured into the output T.
If everything is going into stdout, you can use the diary function to capture that and write it to file, then after execution you can use any number of matlab file reading utilities to parse through it. You might also find the function tempdir and tempname useful in this context.