如何在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.
代码改动点说明
- 新增
Posix.Wait单元引入,该单元包含WEXITSTATUS、WIFEXITED等必要的状态解析宏 - 调整
RunCommand函数,增加out ExitCode: Integer参数用于返回退出状态 - 修复原代码中
Result被每次循环覆盖的问题,改为追加输出内容 - 在
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
相关产品推荐
相关产品推荐

