Я нашел вопрос это, и первый ответ содержит пример кода, демонстрирующий, как запустить исполняемый файл с кодом Ада. Вывод исполняемого файла записывается в стандартный вывод.
Какие параметры у меня есть для чтения вывода исполняемого файла для дальнейшего анализа/обработки в Аде (например, построчно)?
Если вы используете GNAT, возможно, вам стоит взглянуть на Get_Command_Output
в пакете GNAT.Expect
. Вот пример:
with Ada.Text_IO, GNAT.Expect;
procedure Main is
Command : constant String := "gnat";
Argument_1 : aliased String := "--version";
Input : constant String := "";
Status : aliased Integer := 0;
-- Execute the command and retrieve the output.
Output : String :=
GNAT.Expect.Get_Command_Output
(Command => Command,
Arguments => (1 => Argument_1'Unchecked_Access),
Input => Input,
Status => Status'Access,
Err_To_Out => False);
-- NOTE: Cheating with Unchecked_Access, OK for demo. You may want
-- to properly new and Free these strings (see Argument_List
-- type in package GNAT.OS_Lib).
begin
Ada.Text_IO.Put_Line (Output);
end Main;
Программа возвращается после выполнения:
$ ./main
GNAT Community 2019 (20190517-83)
Copyright (C) 1996-2019, Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Как видно, результат возвращается в виде одной строки. Вам придется сделать разделение линии самостоятельно.
Обновлять
Обновление в ответ на некоторые комментарии ниже.
Вы также можете рассмотреть возможность использования функции system
, если вы ориентируетесь на платформу Windows (см. также пост это на SO). Цитата из ссылки на функцию:
The system function passes command to the command interpreter, which executes the string as an operating-system command.
Это похоже на то, что делает программа cmd.exe
. Вы можете получить вывод команды, перенаправив ее вывод в файл (т. е. используя >
), а затем прочитать его обратно. Вот пример:
with Ada.Text_IO;
with Ada.Text_IO.Unbounded_IO;
with Ada.Strings.Unbounded;
with Interfaces.C;
with Interfaces.C.Strings;
procedure Main is
use Ada.Strings.Unbounded;
Content : Unbounded_String := Null_Unbounded_String;
begin
-- Execute.
declare
use Interfaces.C;
use Interfaces.C.Strings;
function system (command : chars_ptr) return int
with Import, Convention => C, External_Name => "system";
command : chars_ptr := New_String("gnat --version > gnat_version.out");
result : int := system (command);
begin
-- Check value of result (omitted in this example).
Free(Command);
end;
-- Read.
declare
use Ada.Text_IO;
use Ada.Text_IO.Unbounded_IO;
Fd : File_Type;
begin
Open (Fd, In_File, "./gnat_version.out");
while not End_Of_File (Fd) loop
Content := Content
& Unbounded_String'(Get_Line (Fd))
& ASCII.CR & ASCII.LF; -- Restore the line break removed by Get_Line.
end loop;
Close (fd);
end;
-- Show.
Ada.Text_IO.Unbounded_IO.Put (Content);
end Main;
Ваш пример кода работает нормально, но я заметил странное поведение (в Windows 7): если одна задача циклически выполняет ваш пример кода, а другая задача записывает в стандартный вывод, используя Ada.Text_IO.Put_Line
, часто бывает, что переменная Output
содержит не ожидаемый результат выполняемая программа, но последняя или несколько строк, которые были записаны второй задачей в стандартный вывод. Я что-то пропустил?
Я подозреваю, что GNAT.Expect.Get_Command_Output
не является потокобезопасным. В частности, поскольку Get_Command_Output
взаимодействует со стандартными потоками (stdin
, stdout
и stderr
) под капотом (см., например, здесь), я бы избегал одновременного выполнения Get_Command_Output
и любых других подпрограмм, связанных со стандартными потоками (например, от Put_Line
до stdout
), чтобы предотвратить условия гонки или другие виды неожиданного поведения.
Хорошо, я не могу избежать одновременного исполнения. Я использую мьютекс на основе типа GNAT.Semaphores.Binary_Semaphore
, чтобы предотвратить одновременное выполнение нескольких команд из разных задач. Я попробовал процедуру этоSpawn
и прочитал содержимое файла в строку, используя метод это. К сожалению, результат тот же. Как я могу выполнить команду на системном уровне, используя перенаправление вывода? Например: ls > /path/to/output-file.txt
.
Из того, что я прочитал в комментариях рядом с функцией Spawn
(см. здесь), создание нового процесса из задачи в целом проблематично, и его следует избегать. Комментарии также предоставляют возможное решение (см. здесь). Я расширил свой ответ небольшим примером того, как вы можете выполнить команду на системном уровне (только для Windows), но я не могу гарантировать, что она будет работать, когда она выполняется из задачи.
Один из вариантов - использовать канал, как объясняется в этом вопросе: stackoverflow.com/questions/48187514/…