You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Delphi 10.4中运行Linux命令并获取进程退出码?

在Ubuntu 18.04 + Delphi 10.4中获取命令进程的退出码

完全可以获取进程的退出码,你当前使用的pclose()函数的返回值就包含了目标进程的终止状态,只需要通过POSIX标准的状态解析宏来提取实际的退出码即可。

关键说明

pclose()的返回值并非直接是退出码:

  • 若进程正常退出,返回值可以通过WEXITSTATUS()宏提取出实际的退出码(范围0-255)
  • 若进程被信号终止,可通过WTERMSIG()宏获取终止进程的信号编号
  • 返回值为-1时表示pclose()调用失败(比如管道出错)

修改后的TestRunCommand单元代码

我们将原RunCommand函数修改为同时返回命令输出和退出码:

unit TestRunCommand;

interface

uses
  System.SysUtils,
  Posix.Base,
  Posix.Fcntl,
  Posix.Wait; // 引入包含状态解析宏的单元

type
  TStreamHandle = pointer;

function popen(const command: MarshaledAString; const _type: MarshaledAString): TStreamHandle; cdecl; external libc name _PU + 'popen';
function pclose(filehandle: TStreamHandle): int32; cdecl; external libc name _PU + 'pclose';
function fgets(buffer: pointer; size: int32; Stream: TStreamHandle): pointer; cdecl; external libc name _PU + 'fgets';
function RunCommand(const aCommand: MarshaledAString; out ExitCode: Integer): String; forward;

implementation

function RunCommand(const aCommand: MarshaledAString; out ExitCode: Integer): String;
var
  handle: TStreamHandle;
  data: array [0 .. 511] of uint8;
  pCloseStatus: int32;

  function bufferToString(buffer: pointer; maxSize: uint32): string;
  var
    cursor: ^uint8;
    endOfBuffer: nativeuint;
  begin
    Result := '';
    if not Assigned(buffer) then
      Exit;
    cursor := buffer;
    endOfBuffer := NativeUInt(cursor) + maxSize;
    while (NativeUInt(cursor) < endOfBuffer) and (cursor^ <> 0) do
    begin
      Result := Result + Chr(cursor^);
      cursor := pointer(succ(NativeUInt(cursor)));
    end;
  end;

begin
  Result := '';
  ExitCode := -1; // 默认值表示执行失败
  handle := popen(aCommand, 'r');
  if not Assigned(handle) then
    Exit;

  try
    while fgets(@data[0], sizeof(data), handle) <> nil do
    begin
      Result := Result + bufferToString(@data[0], sizeof(data)); // 修复原代码覆盖输出的问题,改为追加
    end;
  finally
    pCloseStatus := pclose(handle);
    if pCloseStatus <> -1 then
    begin
      if WIFEXITED(pCloseStatus) then
        ExitCode := WEXITSTATUS(pCloseStatus) // 提取正常退出的代码
      else if WIFSIGNALED(pCloseStatus) then
        ExitCode := -WTERMSIG(pCloseStatus); // 用负数值表示被信号终止,方便区分
    end;
  end;
end;

end.

代码改动点说明

  1. 新增Posix.Wait单元引入,该单元包含WEXITSTATUS、WIFEXITED等必要的状态解析宏
  2. 调整RunCommand函数,增加out ExitCode: Integer参数用于返回退出状态
  3. 修复原代码中Result被每次循环覆盖的问题,改为追加输出内容
  4. 在finally块中处理pclose()的返回值,解析出实际的退出码:
    • 用WIFEXITED判断进程是否正常退出
    • 用WEXITSTATUS提取正常退出码
    • 用WIFSIGNALED和WTERMSIG处理被信号终止的情况

使用示例

var
  Output: string;
  ExitCode: Integer;
begin
  Output := RunCommand('ls -l /nonexistent', ExitCode);
  Writeln('命令输出:', Output);
  Writeln('退出码:', ExitCode);
  // 如果目标命令正常退出,ExitCode为命令本身的退出码;如果被信号终止,ExitCode为负的信号编号
end;

内容的提问来源于stack exchange,提问作者Matteo Pasini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 07:01:26