Использование командной строки Windows из Паскаля - PullRequest
4 голосов
/ 04 мая 2010

Я пытаюсь использовать некоторые инструменты командной строки Windows из короткой программы Pascal. Чтобы сделать это проще, я пишу функцию с именем DoShell, которая принимает строку командной строки в качестве аргумента и возвращает тип записи с именем ShellResult, с одним полем для кода выхода процесса и одним полем для выходного текста процесса.

У меня серьезные проблемы с некоторыми функциями стандартной библиотеки, которые работают не так, как ожидалось. Функция DOS Exec () фактически не выполняет команду, которую я ей передаю. Процедура Reset () дает мне ошибку времени выполнения RunError (2), если я не установил режим компилятора {I-}. В этом случае я не получаю ошибки времени выполнения, но функции Readln (), которые я впоследствии использую для этого файла, фактически ничего не читают, и, кроме того, функции Writeln (), используемые после этой точки при выполнении кода, также ничего не делают. 1003 *

Вот исходный код моей программы. Я использую Lazarus 0.9.28.2 beta с Free Pascal Compiler 2.24


program project1;

{$mode objfpc}{$H+}

uses
  Classes, SysUtils, StrUtils, Dos
  { you can add units after this };

{$IFDEF WINDOWS}{$R project1.rc}{$ENDIF}

type
  ShellResult = record
    output    : AnsiString;
    exitcode  : Integer;
  end;

function DoShell(command: AnsiString): ShellResult;
    var
      exitcode: Integer;
      output: AnsiString;
      exepath: AnsiString;
      exeargs: AnsiString;
      splitat: Integer;
      F: Text;
      readbuffer: AnsiString;
    begin
      //Initialize variables
      exitcode   := 0;
      output     := '';
      exepath    := '';
      exeargs    := '';
      splitat    := 0;
      readbuffer := '';
      Result.exitcode := 0;
      Result.output   := '';

      //Split command for processing
      splitat := NPos(' ', command, 1);
      exepath := Copy(command, 1, Pred(splitat));
      exeargs := Copy(command, Succ(splitat), Length(command));

      //Run command and put output in temporary file
      Exec(FExpand(exepath), exeargs + ' >__output');
      exitcode := DosExitCode();

      //Get output from file
      Assign(F, '__output');
      Reset(F);
      Repeat
        Readln(F, readbuffer);
        output := output + readbuffer;
        readbuffer := '';
      Until Eof(F);

      //Set Result
      Result.exitcode := exitcode;
      Result.output   := output;

    end;

var
  I : AnsiString;
  R : ShellResult;
begin
  Writeln('Enter a command line to run.');
  Readln(I);
  R := DoShell(I);
  Writeln('Command Exit Code:');
  Writeln(R.exitcode);
  Writeln('Command Output:');
  Writeln(R.output);
end.

Ответы [ 3 ]

1 голос
/ 10 мая 2010

Не используйте dos.exec, он ограничен короткой (255 символов) командной строкой. Используйте sysutils.executeprocess.

Однако комментарии Михала, вероятно, касаются основной проблемы. При выполнении с помощью функций ядра (не оболочки) всегда следует указывать полный путь. Также, используя функции ядра, нельзя использовать команды оболочки, такие как перенаправление.

В общем, я предлагаю вам попробовать использовать класс TProcess в блоке process. Он абстрагирует все это и многое другое, а также используется Lazarus для вызова внешних инструментов.

1 голос
/ 26 ноября 2013

Вы можете использовать это:

uses sysutils;

begin
    ExecuteProcess('cmd','/c dir C:\foo');
    ExecuteProcess('C:\foo\bar.exe','param1 param2');
end.

Если вы хотите получить выходные данные команды, вы можете захотеть увидеть этот пост. http://wiki.freepascal.org/Executing_External_Programs#TProcess

1 голос
/ 07 мая 2010

При быстром взгляде я вижу, что вы пытаетесь разделить команду на основе пробела. Что делать, если:

  • Я пытаюсь выполнить что-то без параметров, например fpc? (ответ: exepath будет пустым)
  • Я пытаюсь выполнить что-то с полным путем и с пробелом в нем, как C:\Program Files\Edit Plus 3\editplus.exe?

Я попытался Exec(), и, кажется, он работает, когда вы указываете полный путь к исполняемому файлу, который вы хотите запустить, но перенаправление вывода не работает. Посмотрите на: Перенаправление командной строки выполняется интерпретатором командной строки . Однако вы можете выполнить .bat файл, который выполняет перенаправление (создайте временный файл .bat с командой, которую пользователь дает + перенаправление, и запустите этот пакет).

...