Let’s redirect output to standard output and error channels into their respective files from within the Fortran program. Why would you want to do this? For some applications that run for a long time, such as large weather and ocean prediction models that can run for days, it’s useful to write standard output and error streams into files by default. More critically, if you’re running your program in parallel, a convenient way to differentiate the output from different images is to redirect standard output and error streams from each image into their own respective files.
Recall from section 6.1 how we write text to standard output and error channels, as shown in the following listing.
Listing 6.14 Writing to standard output and error streams
program redirect_stdout_to_file
use iso_fortran_env, only: stdout => output_unit, & ❶
stderr => error_unit ❶
implicit none
write(stdout, *) 'This goes to stdout.' ❷
write(stderr, *) 'This goes to stderr.' ❸
end program redirect_stdout_to_file
❶ Gets standard output and error unit constants from the built-in module
❷ Writes some text to standard output
❸ Writes some text to standard error
If you compile and run this program as is, both messages will be printed to screen:
./redirect_stdout_to_file
This goes to stdout.
This goes to stderr.
However, with shell redirection, we can confirm that each of these messages indeed goes to its respective standard stream:
./redirect_stdout_to_file 1> log.out 2> log.err
cat log.out
This goes to stdout.
cat log.err
This goes to stderr.
Now, how do we redirect the output within our Fortran program such that log.out and log.err files are written without the help of shell redirection? The solution is simple, though perhaps not immediately obvious. Open a file log.out while assigning it an I/O unit number of stdout, and likewise for stderr. The following listing provides the complete program.
Listing 6.15 Redirecting standard output and error streams to their own files
program redirect_stdout_to_file
use iso_fortran_env, only: stdout => output_unit, & ❶
stderr => error_unit ❶
implicit none
open(stdout, file='log.out') ❷
open(stderr, file='log.err') ❷
write(stdout, *) 'This goes to stdout.' ❸
write(stderr, *) 'This goes to stderr.' ❹
close(stdout) ❺
close(stderr) ❺
end program redirect_stdout_to_file
❶ Gets standard output and error unit constants from the built-in module
❷ Opens a file for each of the stdout and stderr I/O units
❸ Writes some text to standard output, now redirected to log.out
❹ Writes some text to standard error, now redirected to log.err
And voilà, we’re done! By opening files and assigning them reserved stdout and stderr I/O units, you’re effectively instructing the compiler to send any output intended for standard streams into these files. This will apply to print statements as well! For example, if you type print *, 'where will this go?', the text will be written to log.out rather than the screen.