sys_run_command Subroutine

public subroutine sys_run_command(command, output, exit_code, timeout)

Run a command and capture output

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: command
character(len=*), intent(out) :: output
integer, intent(out) :: exit_code
integer, intent(in), optional :: timeout

Source Code

    subroutine sys_run_command(command, output, exit_code, timeout)
        character(len=*), intent(in) :: command
        character(len=*), intent(out) :: output
        integer, intent(out) :: exit_code
        integer, intent(in), optional :: timeout
        character(len=1024) :: full_command, temp_file
        integer :: unit, iostat

        ! Initialize output and exit_code
        output = ""
        exit_code = -1

        ! Check for empty or invalid command
        if (len_trim(command) == 0) then
            output = "Error: Empty command"
            exit_code = 127  ! Command not found
            return
        end if

        temp_file = create_temp_file('sys_cmd_output', '.tmp')

        ! Build the command carefully, wrapping in shell to handle edge cases
        if (get_os_type() == OS_WINDOWS) then
            if (present(timeout)) then
                ! Windows doesn't have a simple timeout command
                full_command = 'cmd /c "'//trim(command)//' > "'//trim(escape_shell_arg(temp_file))//'" 2>&1"'
            else
                full_command = 'cmd /c "'//trim(command)//' > "'//trim(escape_shell_arg(temp_file))//'" 2>&1"'
            end if
        else
            if (present(timeout)) then
    write (full_command, '(A,I0,A)') 'sh -c ''timeout ', timeout, ' '//trim(command)// &
                    ' > "'//trim(escape_shell_arg(temp_file))//'" 2>&1'''
            else
                full_command = 'sh -c '''//trim(command)//' > "'//trim(escape_shell_arg(temp_file))//'" 2>&1'''
            end if
        end if

        ! Use cmdstat to catch invalid command errors
        call execute_command_line(full_command, exitstat=exit_code, cmdstat=iostat)

        ! Handle command execution errors
        if (iostat /= 0) then
            exit_code = 127  ! Command not found
            output = "Command execution failed"
            call sys_remove_file(temp_file)
            return
        end if

        output = ""
        open (newunit=unit, file=temp_file, status='old', iostat=iostat)
        if (iostat == 0) then
            read (unit, '(A)', iostat=iostat) output
            close (unit)
        end if

        call sys_remove_file(temp_file)
    end subroutine sys_run_command