Fortranのプログラム中で,コマンドライン引数を取得する方法をまとめます.
ネット上にいくつか記事が見られますが,まだ非標準の手続きを使っている場合もあります.本記事では,Fortran 2003から追加された標準手続きを利用します.Fortran2018から少し変わっている部分もあるので,それについても言及します.
以前に記事の付録としてまとめていますが,改めて一つの記事として切り出しています.
概要
- Fortranでコマンドライン引数を取得するには,サブルーチン
get_command_argument
を利用する. - 定石として,
get_command_argument(number,length)
でn番目の引数の長さを取得して文字列を割付けた後,get_command_argument(number,value)
で引数の文字列を取得する. - サブルーチン実行の成否は整数(0なら成功,それ以外なら失敗)として取得できるが,Fortran2018からはエラーメッセージも取得できるようになっている.
環境
- gfortran 8.1.0 (Windows, Linux)
- intel fortran 2021.1 (Windows, Linux)
- nvfortran 20.11-0 (Linux)
Fortran標準の手続によるコマンドライン引数の取得
Fortran 2003から,コマンドライン引数に関する手続き(サブルーチンまたは関数)が追加されました.
コマンドライン引数全体を取得するサブルーチンget_command()
,引数の個数を取得するcommand_argument_count()
関数,各引数を取得するサブルーチンget_command_argument()
です.
関数 | 機能 |
---|---|
get_command([command = コマンドライン引数, length = コマンドライン引数の長さ, status=取得状態]) |
コマンドライン引数全体を取得するcommand 引数が指定された場合,実行コマンドも含む全てのコマンドライン引数を文字列として取得するlength 引数が指定された場合,コマンドライン引数の文字列の長さを取得するstatus は,コマンドライン引数を正常に取得できれば0,文字列の変数がコマンドライン引数よりも短ければ-1,それ以外で正常に取得できなかった場合は正の値 |
command_argument_count() |
実行コマンドを含まない引数の個数を標準種別の整数型で返す |
get_command_argumet(number=引数番号, [value = 引数の値(文字列), length = 引数の長さ, status=取得状態]) |
指定された番号(0 $\le$number $\le$command_argument_count() )の引数を取得する(0は実行コマンド)value 引数が指定された場合,指定された番号の引数を文字列として取得するlength 引数が指定された場合,指定された番号の引数の文字列長さを取得するstatus は,引数を正常に取得できれば0,文字列の変数が引数よりも短ければ-1,それ以外で正常に取得できなかった場合は正の値 |
get_command
やget_command_argument
の引数command
, length
, value
は省略可能ですが,現実的な使い方としてすべてを省略することはないでしょう.
個別の引数は,下記の手順で取得すると無駄がありません.使う変数名などは異なりますが,他の記事でも同様の手順で引数が取得されており,定石といってよいでしょう.
-
command_argumet_count()
での個数を取得 -
do
ループの中でget_command_argument()
によって各引数の長さを取得 - 取得した長さの文字列を動的に割り付けて
get_command_argument()
で引数を取得
program main
use, intrinsic :: iso_fortran_env
implicit none
type :: arguments
character(:), allocatable :: v
end type
integer(int32) :: argc
type(arguments), allocatable :: arg(:)
argc = command_argument_count() ! 実行コマンドを含まない引数の個数
allocate (arg(0:argc)) ! 実行コマンド+引数を格納するための文字列配列
get_arguments: block
integer(int32) :: n, length_nth_arg
do n = 0, argc
! 第n引数の長さを取得
call get_command_argument(number=n, length=length_nth_arg)
! 第n引数の長さと同じ長さの文字列を割付
allocate (character(length_nth_arg) :: arg(n)%v)
! 第n引数の値を文字列で取得
call get_command_argument(number=n, value=arg(n)%v)
print *, n, arg(n)%v
end do
end block get_arguments
end program main
上記のプログラムでは,C言語の流儀に従って,コマンドライン引数の個数をargc
,引数の文字列をargv
と表現するようにしています.引数の文字列の格納には,自動割付文字列を成分に持つ構造体arguments
型を作成し,そのarguments
型の配列を利用しています.
上記のプログラムをコンパイルして実行すると,実行コマンドを含む引数の番号とその文字列が出力されます.
$ ./a.out --help --version
0 ./a.out
1 --help
2 --version
エラー処理
サブルーチンで引数を正しく取得できているか否かを確認するには,status
引数として整数型変数を渡します.サブルーチン実行後にその値を確認し,その値に応じて処理を切り分けます.
program main
use, intrinsic :: iso_fortran_env
implicit none
! 中略
integer(int32) :: stat
! 中略
call get_command_argument(number=n, value=arg(n)%v, status=stat)
if (stat /= 0) then
write (error_unit, '(*(g0))') "error in get_command_argument: &
&unable to get correctly the string of argument : ", n
stop
end if
! 中略
end program main
status
の値を確認することで,実行の成否が確認できます.したがって,status
はエラーコードと見ることも可能ですが,エラーコードと生じているエラーの対応関係は,規格では規定されていないようです.
Intel Fortranの実行時エラーについては,一覧が存在しています.
Fortran 2018での拡張
上述したように,サブルーチンの引数status
でエラーコードを取得できますが,エラーコードと生じているエラーの対応を調べるのも一苦労です.
Fortran 2018からは,get_command
とget_command_argument
に新たな引数errmsg
が追加されました.この引数を利用すると,引数として渡した文字列にエラーメッセージが書き込まれます.status
と併せて利用することで,status
が0
でない場合にエラーの内容を表示できます.
program main
use, intrinsic :: iso_fortran_env
implicit none
type :: arguments
character(:), allocatable :: v
end type
integer(int32) :: argc, stat
type(arguments), allocatable :: arg(:)
integer(int32), parameter :: len_buffer = 255
character(len_buffer) :: error_message
argc = command_argument_count() ! 実行コマンドを含まない引数の個数
allocate (arg(0:argc)) ! 実行コマンド+引数を格納するための文字列配列
get_arguments: block
integer(int32) :: n, length_nth_arg
do n = 0, argc
! 第n引数の長さを取得
call get_command_argument(number=n, length=length_nth_arg, status=stat, errmsg=error_message)
if (stat /= 0) then
write (error_unit, '(*(g0))') trim(error_message)
stop
end if
! 第n引数の長さと同じ長さの文字列を割付
allocate (character(length_nth_arg) :: arg(n)%v)
! 第n引数の値を文字列で取得
call get_command_argument(number=n, value=arg(n)%v, status=stat, errmsg=error_message)
if (stat /= 0) then
write (error_unit, '(*(g0))') trim(error_message)
stop
end if
print *, n, arg(n)%v
end do
end block get_arguments
end program main
例えば,存在しない引数の番号を指定してしまった場合には
Empty arg in retrieved command
というエラーメッセージが表示されます.
残念ながら,Fortran 2018相当のget_command
とget_command_argument
が利用できるのは,テストした限りではIntel Fortranのみです.
Fortranでは,文字列にallocatable
属性を付けると,自動割付文字列という扱いになり,文字列にリテラルなどを代入する際に,その長さが自動で変化します.しかし,この自動割付は代入時にしか有効ではないので,引数errmsg
に未割付の文字列を渡すと,実行時エラーとなります.そのため,上記のプログラムでは,errmsg
に相当する文字列error_message
は長さを固定し,出力の際にtrim
関数で文字列後部の空白を消しています.
Fortranの次の規格(おそらくFortran 2023)では,自動割付は代入時のみという制約が外れるので,今後はもっと使いやすくなると予想されます.