Fortran command-line arguments
last modified November 14, 2026
A program that reads its settings from the command line is easier to reuse than
one that hard-codes them: the same binary can process any file, repeat a task
any number of times or run in a verbose mode. The shell splits the line into
words, removes the quotes, and passes the result to the program as an array of
strings, one string per argument. Fortran does not expose that array directly;
two intrinsics read it, command_argument_count for the number of
arguments and get_command_argument for the text of one of them.
This article reads the arguments, converts them to numbers with
iostat checks, writes a small option parser, produces usage
messages and meaningful exit codes, skips arguments that do not parse,
investigates how the shell treats spaces and quotes, and shows what happens
when the receiving variable is too short. The programs are run with arguments,
and the outputs below show the exact command lines that produced them.
Counting and reading the arguments
command_argument_count() returns the number of arguments, not
counting the program name, and call get_command_argument(i, value)
copies the i-th one into a character variable. Two optional
arguments add information: length receives the real length of the
argument, which may be larger than the variable, and status
receives zero on success. A third intrinsic, get_command, returns
the whole line including the program name and the spacing, exactly as the shell
passed it.
program a1
implicit none
character(len=80) :: arg, whole
integer :: i, count, length, status
count = command_argument_count()
print '(a, i0)', 'argument count: ', count
do i = 1, count
call get_command_argument(i, arg, length, status)
print '(i2, a, a, a, i0, a, i0)', i, ' "', arg(1:length), &
'" length ', length, ', status ', status
end do
call get_command(whole)
print '(a, a)', 'the whole command: ', trim(whole)
end program a1
Three arguments arrive from the line ./a1 alpha beta 7: the words
are split at the spaces and the quotation marks are gone. One important
difference from C is that the program name is not an element of the argument
list, so the loop starts at one and ends at the count, and the name appears
only in the string returned by get_command. The length reported for
each argument is its length as the shell passed it, without the padding that
the fixed-length variable adds.
$ gfortran a1.f90 -o a1 $ ./a1 alpha beta 7 argument count: 3 1 "alpha" length 5, status 0 2 "beta" length 4, status 0 3 "7" length 1, status 0 the whole command: ./a1 alpha beta 7 $ ./a1 argument count: 0 the whole command: ./a1
Turning text into numbers
Every argument arrives as text, even one that looks like a number. The internal
file read read(arg, *, iostat=status) x applies the same rules as
a read from the keyboard: leading spaces are ignored, a decimal point makes the
value real, and anything else sets status to a nonzero value
instead of stopping the program. The same text can be read twice, once into a
real and once into an integer, and the two attempts may disagree, which is how
a program distinguishes 42 from 2.5.
program a2
implicit none
character(len=32) :: arg
integer :: n, status
real :: x
call get_command_argument(1, arg, status=status)
if (status /= 0) then
print '(a)', 'no argument was given'
stop
end if
read (arg, *, iostat=status) x
if (status == 0) then
print '(a, f0.4)', 'as a real: ', x
print '(a, es10.3)', 'squared: ', x * x
else
print '(a, a, a)', '"', trim(arg), '" is not a real number'
end if
read (arg, *, iostat=status) n
if (status == 0) then
print '(a, i0)', 'as an integer: ', n
print '(a, i0)', 'doubled: ', 2 * n
else
print '(a, a, a)', '"', trim(arg), '" is not an integer'
end if
end program a2
The integer 42 converts to both types and is doubled; 2.5 converts only to a
real, and the integer attempt fails as it should; the word hello
fails both times. The last run has no argument at all, which
get_command_argument reports through its status rather than by
returning an empty string, so the program can tell a missing argument from an
empty one. Checking the status after every conversion is what keeps a typo on
the command line from turning into a silent zero.
$ gfortran a2.f90 -o a2 $ ./a2 42 as a real: 42.0000 squared: 1.764E+03 as an integer: 42 doubled: 84 $ ./a2 2.5 as a real: 2.5000 squared: 6.250E+00 "2.5" is not an integer $ ./a2 hello "hello" is not a real number "hello" is not an integer $ ./a2 no argument was given
A small option parser
Options are conventions, not a language feature. The usual convention is that
an argument beginning with a hyphen is an option, a bare word is a positional
argument, and an option that takes a value consumes the next argument. The
parser below walks the list with an index it can advance by two, handles each
option in a select case, and stores the result in ordinary
variables with defaults set before the loop.
program a3
implicit none
character(len=64) :: arg, name
integer :: i, count, n, status
logical :: upper
n = 1
upper = .false.
name = 'world'
count = command_argument_count()
i = 1
do while (i <= count)
call get_command_argument(i, arg)
select case (trim(arg))
case ('-n')
i = i + 1
call get_command_argument(i, arg)
read (arg, *, iostat=status) n
if (status /= 0 .or. n < 1 .or. n > 10) then
print '(a)', 'the -n option needs a number from 1 to 10'
stop 2
end if
case ('-u')
upper = .true.
case default
if (arg(1:1) == '-') then
print '(a, a)', 'unknown option: ', trim(arg)
stop 2
end if
name = arg
end select
i = i + 1
end do
if (upper) name = to_upper(trim(name))
do i = 1, n
print '(a, i0, a, a, a)', 'hello ', i, ', ', trim(name), '!'
end do
if (n > 1) print '(a, i0, a)', 'that was ', n, ' greetings'
contains
function to_upper(text) result(out)
character(len=*), intent(in) :: text
character(len=len(text)) :: out
integer :: k
out = text
do k = 1, len(text)
if (out(k:k) >= 'a' .and. out(k:k) <= 'z') then
out(k:k) = achar(iachar(out(k:k)) - 32)
end if
end do
end function to_upper
end program a3
With no arguments the program uses its defaults: one greeting to the world. The
second run sets the count to three with -n 3, turns on the
uppercase conversion with -u, and supplies the name as a
positional argument. The third run shows that -n 2 keeps the
default name, because no positional argument followed it. An unknown option
prints a message and stops with status 2, which is the conventional code for a
usage error.
$ gfortran a3.f90 -o a3 $ ./a3 hello 1, world! $ ./a3 -n 3 -u fortran hello 1, FORTRAN! hello 2, FORTRAN! hello 3, FORTRAN! that was 3 greetings $ ./a3 -n 2 hello 1, world! hello 2, world! that was 2 greetings $ ./a3 -x; echo "exit status: $?" unknown option: -x STOP 2 exit status: 2
Usage messages and exit status
A program that cannot continue should say why on the standard error
stream, not on standard output, because the output may be redirected to a file
while the complaint must still reach the terminal. The constant
error_unit from iso_fortran_env is that stream. The
number passed to stop becomes the exit status seen by the shell:
zero means success, and small nonzero values have conventional meanings, 1 for
a runtime failure and 2 for bad usage.
program a4
use iso_fortran_env, only: error_unit
implicit none
character(len=256) :: path, line
integer :: lines, unit, ios
if (command_argument_count() /= 1) then
write (error_unit, '(a)') 'usage: a4 FILE'
stop 2
end if
call get_command_argument(1, path)
open (newunit=unit, file=trim(path), status='old', action='read', &
iostat=ios)
if (ios /= 0) then
write (error_unit, '(a, a)') 'cannot open ', trim(path)
stop 1
end if
lines = 0
do
read (unit, '(a)', iostat=ios) line
if (ios /= 0) exit
lines = lines + 1
end do
close (unit)
print '(a, a)', 'file: ', trim(path)
print '(a, i0)', 'lines: ', lines
end program a4
The program needs exactly one argument, so the count is compared with one
before anything is read. With a file name it opens the file, counts the lines
until the read fails, and prints the total; with no argument it prints the usage
line and exits with 2; with a name that does not exist the open fails and it
exits with 1. The shell command echo "exit status: $?" prints the
status of the preceding command, and the values 2 and 1 in the transcript are
the ones the program chose.
$ gfortran a4.f90 -o a4 $ printf 'alpha\nbeta\ngamma\n' > words.txt $ ./a4 words.txt file: words.txt lines: 3 $ ./a4; echo "exit status: $?" usage: a4 FILE STOP 2 exit status: 2 $ ./a4 missing.txt; echo "exit status: $?" cannot open missing.txt STOP 1 exit status: 1
Skipping arguments that do not parse
Not every bad argument deserves a fatal error. A tool that adds numbers can
ignore a word it cannot convert, report it and continue with the rest, which is
friendlier when the arguments come from a script that may pass an occasional
comment. The pattern is the same iostat test, with the failure
branch printing a warning instead of stopping.
program a5
implicit none
character(len=32) :: arg
integer :: i, count, value, total, good, status
count = command_argument_count()
total = 0
good = 0
do i = 1, count
call get_command_argument(i, arg)
read (arg, *, iostat=status) value
if (status == 0) then
total = total + value
good = good + 1
else
print '(a, a, a)', 'skipping "', trim(arg), '", not an integer'
end if
end do
print '(a, i0)', 'numbers read: ', good
print '(a, i0)', 'their sum: ', total
if (count == 0) print '(a)', 'usage: a5 NUMBER [NUMBER ...]'
end program a5
The first run adds five numbers to 15. The second run meets the word
x, reports it, and still adds the other four values, including the
negative one, which the read accepts without complaint. The count is of the
numbers that were accepted, not of the arguments that were given, and the last
run with no arguments prints the usage line after the two totals, since a
program that prints a summary first and a hint afterwards reads better than one
that produces nothing at all.
$ gfortran a5.f90 -o a5 $ ./a5 1 2 3 4 5 numbers read: 5 their sum: 15 $ ./a5 10 -4 7 x 3 skipping "x", not an integer numbers read: 4 their sum: 16 $ ./a5 numbers read: 0 their sum: 0 usage: a5 NUMBER [NUMBER ...]
Spaces, quotes and empty arguments
The shell, not Fortran, decides where one argument ends and the next begins. Double or single quotes keep a space inside one argument, a quoted empty string becomes an argument of length zero, and the quotes themselves disappear before the program ever sees the text. This matters for a program that builds a command for another program, because the quoting has to be added back.
program a6
implicit none
character(len=128) :: arg
integer :: i, count, length, status, total
count = command_argument_count()
total = 0
print '(a, i0)', 'arguments: ', count
do i = 1, count
call get_command_argument(i, arg, length, status)
total = total + length
print '(i2, a, a, a, i0, a, i0)', i, ' [', arg(1:length), &
'] length ', length, ', status ', status
end do
print '(a, i0)', 'characters in all: ', total
end program a6
The first argument is hello world, eleven characters including the
space, and it arrives as one string rather than two. The third argument is
empty: its length is zero, its status is zero, and the bracket pair with
nothing between them is how the program shows that the argument exists. The
total of seventeen characters is the sum of the three lengths.
$ gfortran a6.f90 -o a6 $ ./a6 "hello world" second "" arguments: 3 1 [hello world] length 11, status 0 2 [second] length 6, status 0 3 [] length 0, status 0 characters in all: 17 $ ./a6 arguments: 0 characters in all: 0
Truncation and the whole command line
A fixed-length variable may be shorter than the argument the user typed. In
that case get_command_argument copies what fits and sets
status to a negative value, which is the signal that the text was
truncated. The optional length argument still reports the full
length, so a program can allocate a wider buffer, or refuse the argument, or
simply warn. Concatenating the pieces of several arguments with a space between
them rebuilds a command line for a shell, exactly as get_command
would return it.
program a7
implicit none
character(len=8) :: small
character(len=64) :: arg, joined
integer :: i, count, length, status, used
call get_command_argument(1, small, length, status)
print '(a, a, a)', 'the first eight characters: "', small, '"'
print '(a, i0)', 'the real length: ', length
print '(a, i0)', 'status with an eight-char buffer: ', status
call get_command_argument(1, arg, length, status)
print '(a, a, a)', 'with a wider buffer: "', arg(1:length), '"'
print '(a, i0)', 'status now: ', status
count = command_argument_count()
joined = ''
used = 0
do i = 1, count
call get_command_argument(i, arg, length, status)
if (used + length + 1 > len(joined)) exit
joined(used + 1:used + length) = arg(1:length)
used = used + length
if (i < count) then
joined(used + 1:used + 1) = ' '
used = used + 1
end if
end do
print '(a, a)', 'the arguments joined: ', joined(1:used)
end program a7
The first attempt reads into eight characters and gets 01234567
with status -1, while the length is the full twenty. A wider buffer takes the
whole argument and the status becomes zero, which is the test a program should
use before trusting the text. The joined string at the end puts the two
arguments back together with a single space, the form in which the shell split
them, and a program that passes that string to another command must quote any
part that still contains a space.
$ gfortran a7.f90 -o a7 $ ./a7 0123456789abcdefghij second the first eight characters: "01234567" the real length: 20 status with an eight-char buffer: -1 with a wider buffer: "0123456789abcdefghij" status now: 0 the arguments joined: 0123456789abcdefghij second
Next steps
The internal files article explains the
read from a character variable in more detail, and the
strings article covers the slicing,
concatenation and comparison used by the parser. The
files article shows the open with
newunit and iostat that the file-counting program
uses, the procedures article explains the
contains block with the uppercase function, the
conditionals article covers the
select case construct, and the
program structure article describes
the layout conventions of the source files.
Source
Fortran 2018 standard (J3/18-007r1)
GNU Fortran manual: COMMAND_ARGUMENT_COUNT
GNU Fortran manual: GET_COMMAND_ARGUMENT
In this article we have counted and read the command-line arguments, converted
them to reals and integers with iostat, written an option parser
with defaults, printed usage messages to error_unit and returned
exit statuses 1 and 2, skipped arguments that do not parse, seen how the shell
treats quotes and empty arguments, detected truncation with a negative status,
and rebuilt a command line by concatenation. The previous article,
Fortran date and time, reads the clock
with the same care about status arguments.
Author
List all Fortran tutorials.