MATLAB & GNU Octave Module 1 – Start here: MATLAB, Octave and a working setup
Scripts, the current folder and the search path
Write Octave and MATLAB scripts with comments and sections, control which file runs through the current folder and the search path, and build portable paths.
What you will learn
- Write and run script files with comments and %% sections
- Predict which file runs from the current folder, the search path and the function precedence order
- Build file paths that work on Windows, macOS and Linux
- Organise a small research project so that it runs from any folder
Before you start
What you’ll learn · Before you start
What you will learn
- Write and run script files with comments and %% sections
- Predict which file runs from the current folder, the search path and the function precedence order
- Build file paths that work on Windows, macOS and Linux
- Organise a small research project so that it runs from any folder
Before you start
On this page
A script that reads data/loads.txt works when you run it from its own folder and stops with load: unable to find file data/loads.txt when a colleague runs it from the folder above. Which file Octave runs, and which file a script
opens, both depend on two things: the current folder and the search path.
Below you write a script with comments and sections, follow the order in which Octave looks up a name and see one stray file hide a function, add a folder of tools to the search path for one session, build file paths that work on Windows, macOS and Linux, and organise a small project that runs from any folder.
A script is a file of commands that runs in your workspace
A script file: A text file of commands ending in .m that runs as if its lines were typed at the prompt, in the same workspace, so its variables remain after it ends. is a plain text file of commands ending in .m. Running it is like typing
its lines at the prompt, one after another. This one follows a cup of tea as it cools, by Newton’s law of cooling, and
uses all three kinds of comment:
%% cooling.m: a cup of tea cooling in a room, by Newton's law of cooling
% Each line that starts with %% begins a section, which an editor can run on
% its own. A % starts a comment that runs to the end of the line.
%{
The model: T(t) = T_room + (T0 - T_room) * exp(-k * t),
with t in minutes and k, the cooling constant, per minute.
%}
%% Inputs
T_room = 25; % room temperature, degrees C
T0 = 90; % temperature of the fresh tea, degrees C
k = 0.05; % cooling constant, per minute
%% Temperature after 10, 20 and 30 minutes
t = [10 20 30];
T = T_room + (T0 - T_room) * exp(-k * t);
fprintf('After %2d min: %.1f C\n', [t; T]); %starts a comment that runs to the end of the line, in MATLAB and Octave alike.%{and%}, each alone on its line, enclose a block comment, here the model in words.%%at the start of a line begins a code section: A part of a script that begins with a line starting with %%. MATLAB's editor can run one section at a time, and Octave's publish uses sections as headings.. MATLAB’s editor runs one section at a time with Run Section, and Octave’spublishturns sections into the headings of a report.
# comments work only in Octave, as the first lesson’s labels showed. Here is the script run by its name at the
prompt, followed by two more lines:
from session import prompt, version
version()
prompt("cooling_prompt.m") Output
# GNU Octave (aarch64-apple-darwin25.4.0) version 11.3.0 $ octave-cli --quiet octave:1> cooling After 10 min: 64.4 C After 20 min: 48.9 C After 30 min: 39.5 C octave:2> who Variables visible from the current scope: T T0 T_room k t octave:3> T_room T_room = 25
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 scripts_session.py
Typing cooling ran the file and printed 64.4, 48.9 and 39.5 degrees after 10, 20 and 30 minutes. Then who listed
T, T0, T_room, k and t: the script’s variables stayed in the workspace, because a script has no workspace of
its own. That is handy at the prompt, where you can look at every value afterwards, and a trap in larger work, where
one script can overwrite another’s variables.
Name a script after what it does
A script runs under its file name, so the name must be a valid variable name: cooling.m runs as cooling, while
tea-cooling.m cannot be run by its name, because tea-cooling reads as a subtraction.
Checkpoint
Check: Script files, comments and sections
Octave looks for a name in a fixed order, and a file can hide a function
When a line uses a name such as mean, Octave searches for it in a fixed order and takes the first match. Here it
searches for mean from report.m, in a folder where a beginner saved a first script as mean.m:
The drawing shows the whole scene; its 7 steps are listed below.
Every step as text
- A variable?. report.m calls mean(loads_kN). Octave first looks for a variable called mean, because a variable hides any function. There is none.
- This file. Next it looks for a function of that name inside report.m itself, or in a folder called private next to it. There is none.
- The current folder. The current folder, shadow_demo, holds a file called mean.m, so Octave stops looking. The file it found is a script.
- The wrong mean. A script takes no inputs, so the call mean(loads_kN) fails with invalid call to script, and Octave warns that the file shadows a core library function.
- Renamed. After mean.m is renamed readings_average.m, the current folder holds no file called mean.m, and the search goes on.
- The search path. The search path lists Octave's own folders, and statistics/mean.m is found there. report.m prints Average load 15 kN.
- Built-in functions. The Octave manual puts built-in functions such as sum after the path, so even a sum.m in the current folder would hide the built-in sum. A name found nowhere is undefined.
Here are the two files and the run, then the same run after the stray file is renamed:
% report.m: the average of three loads, with the mean function.
loads_kN = [12 15 18];
fprintf('Average load: %g kN\n', mean(loads_kN)); % mean.m: a first script, saved under a name a function already has.
readings = [2 4 6];
fprintf('Average of the readings: %g\n', sum(readings) / numel(readings)); from session import run, version
version()
run("""
cd shadow_demo && octave-cli --no-init-all --eval "which mean"
!cd shadow_demo && octave-cli --no-init-all report.m
cd shadow_demo && octave-cli --no-init-all --eval "which -all mean"
cd shadow_demo && mv mean.m readings_average.m
cd shadow_demo && octave-cli --no-init-all report.m
cd shadow_demo && octave-cli --no-init-all --eval "which mean"
""") Output
# GNU Octave (aarch64-apple-darwin25.4.0) version 11.3.0
$ cd shadow_demo && octave-cli --no-init-all --eval "which mean"
warning: function shadow_demo/mean.m shadows a core library function
'mean' is a script from the file shadow_demo/mean.m
$ cd shadow_demo && octave-cli --no-init-all report.m
warning: function shadow_demo/mean.m shadows a core library function
error: invalid call to script shadow_demo/mean.m
error: called from
mean
report at line 3 column 1
[exit status 1]
$ cd shadow_demo && octave-cli --no-init-all --eval "which -all mean"
warning: function shadow_demo/mean.m shadows a core library function
warning: which: '-all' not yet implemented - only the first result will be returned
'mean' is a script from the file shadow_demo/mean.m
$ cd shadow_demo && mv mean.m readings_average.m
$ cd shadow_demo && octave-cli --no-init-all report.m
Average load: 15 kN
$ cd shadow_demo && octave-cli --no-init-all --eval "which mean"
'mean' is a function from the file /opt/homebrew/Cellar/octave/11.3.0_1/share/octave/11.3.0/m/statistics/mean.m
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 shadow_session.py
which mean named the script in the folder, and Octave warned that it “shadows a core library function”. The call
mean(loads_kN) then failed with invalid call to script, because a script takes no inputs. After mv renamed the
file to readings_average.m, report.m printed Average load: 15 kN, and which mean found Octave’s own
statistics/mean.m.
The order is a function precedence order: The fixed order in which MATLAB and Octave look up a name: variables first, then functions in the same file and private folders, then the current folder and the search path.. Octave’s manual lists it from
functions in the same file and private folders down to the folders of the search path and the built-in functions,
and a variable comes before all of them, as sum = 0 showed in the previous lesson. MathWorks documents the same
outline for MATLAB: variables first, then functions in the same file, private functions, the current folder and the
rest of the path.
The third command shows a portability gap: Octave 11.3 answers which -all mean with '-all' not yet implemented
and gives only the first match, while MATLAB’s which -all lists every file of that name on the path.
Saving a script under a function's name
mean.m, sum.m, plot.m or max.m in your folder hides the function for every script run there. Before you
save a new file, type which name with the name you want: an answer that names a built-in function or a file of
Octave’s own means the name is taken.
Checkpoint
Check: The order of name lookup
The search path decides which other folders count
Octave finds a file in the current folder, and beyond it only in the folders of its
search path: The list of folders in which MATLAB and Octave look for function and script files. It starts with the current folder; addpath and rmpath change it for the session., which starts with the current folder and continues with Octave’s own
folders. addpath adds a folder for the rest of the session, rmpath removes it, and genpath lists a folder with
all its subfolders. This session uses a small folder of helper functions, tools/ with a subfolder tools/units/:
function stress_MPa = to_mpa(stress_Pa)
% to_mpa: converts a stress from pascals to megapascals.
stress_MPa = stress_Pa / 1e6;
end from session import prompt, version
version()
prompt("path_prompt.m", flags="--no-init-all") Output
# GNU Octave (aarch64-apple-darwin25.4.0) version 11.3.0
$ octave-cli --no-init-all --quiet
octave:1> exist('to_mpa')
ans = 0
octave:2> addpath('tools')
octave:3> exist('to_mpa')
ans = 2
octave:4> which to_mpa
'to_mpa' is a function from the file tools/to_mpa.m
octave:5> to_mpa(132.6e6)
ans = 132.60
octave:6> rmpath('tools')
octave:7> exist('to_mpa')
ans = 0
octave:8> genpath('tools')
ans = tools:tools/units
octave:9> old_path = path();
octave:10> addpath(genpath('tools'))
octave:11> to_mpa(kn_to_n(15) / 113.1e-6)
ans = 132.63
octave:12> path(old_path);
octave:13> exist('kn_to_n')
ans = 0
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 path_session.py
Before addpath('tools'), exist('to_mpa') was 0: the function’s file is in a subfolder, which the search does not
enter. Afterwards it was 2, a file, and which showed where. rmpath took it away again. genpath('tools') returned
tools:tools/units, the folder and its subfolder separated by pathsep, a colon on macOS and Linux.
The last five lines are the pattern to keep: save the path with old_path = path(), add what the work needs with
addpath(genpath('tools')), do the work, here a stress of 132.63 MPa from the two helpers, and put the old path back
with path(old_path), so the next project starts clean.
Saving the path for every session with savepath
savepath writes the current path into a startup file, so it changes every later session, including other
projects that never wanted those folders. Set the path in the project, as above, and restore it when done.
MathWorks also advises against changing the path while code runs, because MATLAB then recompiles code.
Checkpoint
Check: The search path
fullfile builds paths that work on every system
data/raw/loads.txt is a path for macOS and Linux; Windows writes data\raw\loads.txt. Rather than typing either
separator, let the program choose it:
from session import prompt, version
version()
prompt("paths_prompt.m", flags="--no-init-all") Output
# GNU Octave (aarch64-apple-darwin25.4.0) version 11.3.0
$ octave-cli --no-init-all --quiet
octave:1> f = fullfile('data', 'raw', 'loads.txt')
f = data/raw/loads.txt
octave:2> filesep
ans = /
octave:3> pathsep
ans = :
octave:4> [folder, name, ext] = fileparts(f)
folder = data/raw
name = loads
ext = .txt
octave:5> fullfile('data/', '/raw', 'loads.txt')
ans = data/raw/loads.txt
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 paths_session.py
fullfile('data', 'raw', 'loads.txt') joined the parts with filesep, the separator of the system, / on the Mac
that recorded these runs; on Windows the Octave manual says fullfile uses backslashes. It also cleaned up doubled
separators: fullfile('data/', '/raw', 'loads.txt') gave the same data/raw/loads.txt. fileparts works the other
way, splitting a path into its folder data/raw, its name loads and its extension .txt. On Windows,
filesep('all') returns both slashes, the separators Octave accepts there, so a path read from a file may contain
/ or \; split it with fileparts rather than by searching for one character.
| Task | Portable | Fragile |
|---|---|---|
| Join folder and file names | fullfile('data', 'raw', 'loads.txt') |
'data/raw/loads.txt' |
| Split a path | [folder, name, ext] = fileparts(f) |
cutting the text at '/' |
| Find the separator | filesep |
assuming / or \ |
Checkpoint
Check: Portable file paths
A project that finds its own files runs from any folder
The script of the opening, analysis_fragile.m, opens data/loads.txt, a path relative to the current folder, so
it works only when the current folder is the project’s. run_analysis.m starts by asking where it is, then builds
every path from there:
% analysis_fragile.m: works only when the current folder is the project's.
loads_kN = load('data/loads.txt');
fprintf('Read %d loads\n', numel(loads_kN)); % run_analysis.m: the stress in a 12 mm rod for each load in data/loads.txt,
% written to results/stress.txt. It finds its own folder first, so it works
% from any current folder.
here = fileparts(mfilename('fullpath'));
loads_kN = load(fullfile(here, 'data', 'loads.txt'));
area_mm2 = pi * 12^2 / 4;
stress_MPa = loads_kN * 1e3 / area_mm2; % N per mm^2 is MPa
out_dir = fullfile(here, 'results');
if ~exist(out_dir, 'dir')
mkdir(out_dir);
end
fid = fopen(fullfile(out_dir, 'stress.txt'), 'w');
fprintf(fid, '%4.0f kN: %6.1f MPa\n', [loads_kN'; stress_MPa']);
fclose(fid);
fprintf('Wrote %d stresses to %s\n', numel(stress_MPa), fullfile('results', 'stress.txt')); Step through how run_analysis.m finds its files when it is started from another folder:
The drawing shows the whole scene; its 5 steps are listed below.
Every step as text
- Started from elsewhere. The run starts in some other folder, project/data in the session, and names the script with a path. Relative names such as data/loads.txt would now point to the wrong place.
- Where am I?. mfilename('fullpath') returns the script's own path without .m, and fileparts keeps its folder. The script calls that folder here.
- Read the data. fullfile(here, 'data', 'loads.txt') builds the path to the data from the script's folder, whatever the current folder is, and load reads the four loads.
- Write the results. The results folder is built the same way, created when missing with mkdir, and the stresses are written to results/stress.txt inside the project.
- Same output anywhere. Started from project/data or from the folder above the project, the script reads and writes the same files and prints the same line, Wrote 4 stresses.
Here are both scripts started from three places:
from session import run, version
version()
run("""
cd project && octave-cli --no-init-all analysis_fragile.m
!octave-cli --no-init-all project/analysis_fragile.m
octave-cli --no-init-all --eval "run('project/analysis_fragile.m')"
octave-cli --no-init-all project/run_analysis.m
cd project/data && octave-cli --no-init-all ../run_analysis.m
cat project/results/stress.txt
""") Output
# GNU Octave (aarch64-apple-darwin25.4.0) version 11.3.0
$ cd project && octave-cli --no-init-all analysis_fragile.m
Read 4 loads
$ octave-cli --no-init-all project/analysis_fragile.m
error: load: unable to find file data/loads.txt
error: called from
project/analysis_fragile.m at line 2 column 1
[exit status 1]
$ octave-cli --no-init-all --eval "run('project/analysis_fragile.m')"
Read 4 loads
$ octave-cli --no-init-all project/run_analysis.m
Wrote 4 stresses to results/stress.txt
$ cd project/data && octave-cli --no-init-all ../run_analysis.m
Wrote 4 stresses to results/stress.txt
$ cat project/results/stress.txt
10 kN: 88.4 MPa
15 kN: 132.6 MPa
20 kN: 176.8 MPa
40 kN: 353.7 MPa
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 project_session.py
From inside the project, the fragile script read its 4 loads; from the folder above, it stopped with load: unable to find file data/loads.txt and status 1. run('project/analysis_fragile.m') worked, because run changes into the
script’s folder, runs it and changes back, as both the Octave manual and MathWorks document. run_analysis.m wrote
the same four stresses, from 88.4 to 353.7 MPa, whether it was started from the folder above or from project/data.
Key idea
here = fileparts(mfilename('fullpath')) gives a script its own folder, so every path built with fullfile(here, …) points to the same files whatever the current folder is.
A small research project then needs only a few conventions: scripts at the top of the project folder, inputs in
data/, outputs in results/, helper functions in a folder added with addpath at the start of a session, and
every path built from here.
cd without a folder differs between the two programs
In Octave, cd alone changes to your home folder; in MATLAB, the Octave manual notes, it prints the current
folder. Scripts that build paths from their own location never need cd at all.
Checkpoint
Check: A project that runs from any folder
Practise: make a script run from anywhere
Three exercises, on your own computer, with the files of this page:
- Save
cooling.m, run it by name, then usewhoto see its variables. Rename it totea-cooling.mand try to run it by name: what does Octave say? - Save
report.mand a script calledmean.min one folder, reproduce theinvalid call to scripterror, and repair it by renaming. Check withwhich meanbefore and after. - Copy the
projectfolder withanalysis_fragile.manddata/loads.txt. Change the script so that it builds its path fromhere, asrun_analysis.mdoes, and run it from the project folder, from itsdatafolder and from the folder above. All three runs must printRead 4 loads.
Then test yourself on scripts, name lookup, the search path, file paths and projects. Each question waits for your answer, says at once why it was right or what it missed, and the next one goes where you are least sure:
Practice that adapts to you
Practise this lesson
15 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
Interview questions
Warm-up: in what order does Octave look for a function when a script uses a name?
First it checks for a variable of that name, because a variable hides any function. Then it looks for a function in
the same file and in a private folder beside it, then for a file in the current folder, then in the other folders
of the search path in their order, and the Octave manual places built-in functions after the path. The first match
wins, so a mean.m saved in the current folder hides Octave’s own mean, and a variable called sum hides the
function sum. which name tells you which one a name refers to right now. MATLAB’s documented order has the same
outline: variables first, the current folder before the rest of the path.
Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.
-
Fresher to mid
A thesis script runs only when its own folder is the current folder; from anywhere else it cannot find its data. Your supervisor must run it from another folder on a cluster. How do you fix it, and how do you show the fix works?
Key takeaways
- A script is a
.mfile of commands that runs in your workspace, so its variables stay after it ends;%and%{ … %}are portable comments, and%%starts a section. - Octave takes the first match for a name: a variable, a function in the same file or a private folder, a file in the
current folder, the search path, then the built-in functions, so a stray
mean.mhid the functionmean. which nameshows what a name refers to; in Octave 11.3,which -allgives only the first match.addpathandrmpathchange the search path for the session; savepath()first and restore it afterwards, and leavesavepathalone.fullfile,filepartsandfilesepbuild and split paths for every system, andmfilename('fullpath')withfilepartsgives a script its own folder, so a project runs from any current folder.
Terms in this lesson
- code section
- A part of a script that begins with a line starting with %%. MATLAB's editor can run one section at a time, and Octave's publish uses sections as headings.
- function precedence order
- The fixed order in which MATLAB and Octave look up a name: variables first, then functions in the same file and private folders, then the current folder and the search path.
- script file
- A text file of commands ending in .m that runs as if its lines were typed at the prompt, in the same workspace, so its variables remain after it ends.
- search path
- The list of folders in which MATLAB and Octave look for function and script files. It starts with the current folder; addpath and rmpath change it for the session.
References
- GNU Octave manual: Script Files (The Octave Project Developers)
- GNU Octave manual: Comments (single-line and block comments) (The Octave Project Developers)
- GNU Octave manual: Function Precedence (The Octave Project Developers)
- GNU Octave manual: Manipulating the Load Path (The Octave Project Developers)
- GNU Octave manual: Filesystem Utilities (fullfile, fileparts, filesep) (The Octave Project Developers)
- GNU Octave manual: Function Files (mfilename) (The Octave Project Developers)
- GNU Octave manual: Calling a Function by its Name (run) (The Octave Project Developers)
- GNU Octave manual: Current Working Directory (cd, pwd) (The Octave Project Developers)
- GNU Octave manual: Publishing Octave Script Files (The Octave Project Developers)
- Function Precedence Order (MATLAB) (MathWorks)
- Create and Run Sections in Code (MATLAB) (MathWorks)
- Add Comments to Code (MATLAB) (MathWorks)
- which: locate functions and files (MATLAB) (MathWorks)
- run: run MATLAB script (MATLAB) (MathWorks)
- mfilename: file name of currently running code (MATLAB) (MathWorks)
- Techniques to Improve Performance (MATLAB) (MathWorks)
Report a problem with this lesson
Kept only in this browser. Your Learn progress