本文档解决的问题是:如何使用free pascal 调用bash命令
首先安装free pascal
这里一开始走了弯路,直接pkg search pascal,发现没有....
原来它的名字叫fpc ,所以应该pkg search fpc
pkg search fpc
pkg: No SRV record found for the repo 'FreeBSD'
fpc-3.2.3 Free Pascal compiler with Turbo and Delphi compatibility
fpc-devel-3.3.1.20240503 Free Pascal compiler with Turbo and Delphi (devel)
fpc-devel-source-3.3.1.20240503 Free Pascal compiler with Turbo and Delphi compatibility (source)
fpc-docs-3.2.2 Free Pascal compiler Adobe Acrobat(tm) documentation
fpc-source-3.2.3 Free Pascal compiler with Turbo and Delphi compatibility (source)
pdfpc-4.6.0_6 Keynote-like multi-monitor presentation viewer
也可以从官网下载适合自己的版本:
使用Pascal调用bash
Executing External Programs - Free Pascal wiki
一个例子
// This is a
// FLAWED
// demo program that shows
// how to launch an external program
// and read from its output.
program launchprogram;
// Here we include files that have useful functions
// and procedures we will need.
uses
Classes, SysUtils, Process;
// This is defining the var "AProcess" as a variable
// of the type "TProcess"
// Also now we are adding a TStringList to store the
// data read from the programs output.
var
AProcess: TProcess;
AStringList: TStringList;
// This is where our program starts to run
begin
// Now we will create the TProcess object, and
// assign it to the var AProcess.
AProcess := TProcess.Create(nil);
// Tell the new AProcess what the command to execute is.
AProcess.Executable := '/usr/local/bin/ppcx64';
AProcess.Parameters.Add('-h');
// We will define an option for when the program
// is run. This option will make sure that our program
// does not continue until the program we will launch
// has stopped running. Also now we will tell it that
// we want to read the output of the file.
AProcess.Options := AProcess.Options + [poWaitOnExit, poUsePipes];
// Now that AProcess knows what the commandline is it can be run.
AProcess.Execute;
// After AProcess has finished, the rest of the program will be executed.
// Now read the output of the program we just ran into a TStringList.
AStringList := TStringList.Create;
AStringList.LoadFromStream(AProcess.Output);
// Save the output to a file and clean up the TStringList.
AStringList.SaveToFile('output.txt');
AStringList.Free;
// Now that the output from the process is processed, it can be freed.
AProcess.Free;
end.
编译
fpc ppc.fpc
Free Pascal Compiler version 3.2.2 [2024/04/04] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: FreeBSD for x86-64
Compiling ppc.fpc
Linking ppc
/usr/local/bin/ld.bfd: warning: /usr/local/lib/fpc/3.2.2/units/x86_64-freebsd/rtl/prt0.o: missing .note.GNU-stack section implies executable stack
/usr/local/bin/ld.bfd: NOTE: This behaviour is deprecated and will be removed in a future version of the linker
53 lines compiled, 0.2 sec
执行
./ppc
查看输出:
cat output.txt |more
Free Pascal Compiler version 3.2.2 [2024/04/04] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
/usr/local/bin/ppcx64 [options] <inputfile> [options]
Put + after a boolean switch option to enable it, - to disable it.
@<x> Read compiler options from <x> in addition to the default fpc.cfg
-a The compiler does not delete the generated assembler file
-a5 Don't generate Big Obj COFF files for GNU Binutils older than 2.25 (Windows, NativeNT)
-al List sourcecode lines in assembler file
-an List node info in assembler file (-dEXTDEBUG compiler)
-ao Add an extra option to external assembler call (ignored for internal)
-ap Use pipes instead of creating temporary assembler files
-ar List register allocation/release info in assembler file
-at List temp allocation/release info in assembler file
-A<x> Output format:
-Adefault Use default assembler
-Aas Assemble using GNU AS
-Agas Assemble using GNU GAS
-Agas-darwin Assemble darwin Mach-O64 using GNU GAS
-Amasm Win64 object file using ml64 (Microsoft)
另一个例子,长时间运行的输出
program LargeOutputDemo;
{$mode objfpc}{$H+}
uses
Classes, SysUtils, Process; // Process is the unit that holds TProcess
const
BUF_SIZE = 2048; // Buffer size for reading the output in chunks
var
AProcess : TProcess;
OutputStream : TStream;
BytesRead : longint;
Buffer : array[1..BUF_SIZE] of byte;
begin
// Set up the process; as an example a recursive directory search is used
// because that will usually result in a lot of data.
AProcess := TProcess.Create(nil);
// The commands for Windows and *nix are different hence the $IFDEFs
{$IFDEF Windows}
// In Windows the dir command cannot be used directly because it's a build-in
// shell command. Therefore cmd.exe and the extra parameters are needed.
AProcess.Executable := 'c:\windows\system32\cmd.exe';
AProcess.Parameters.Add('/c');
AProcess.Parameters.Add('dir /s c:\windows');
{$ENDIF Windows}
{$IFDEF Unix}
AProcess.Executable := '/bin/ls';
{$IFDEF Darwin}
AProcess.Parameters.Add('-recursive');
AProcess.Parameters.Add('-all');
{$ENDIF Darwin}
{$IFDEF Linux}
AProcess.Parameters.Add('--recursive');
AProcess.Parameters.Add('--all');
{$ENDIF Linux}
{$IFDEF FreeBSD}
AProcess.Parameters.Add('-R');
AProcess.Parameters.Add('-a');
{$ENDIF FreeBSD}
AProcess.Parameters.Add('-l');
{$ENDIF Unix}
// Process option poUsePipes has to be used so the output can be captured.
// Process option poWaitOnExit can not be used because that would block
// this program, preventing it from reading the output data of the process.
AProcess.Options := [poUsePipes];
// Start the process (run the dir/ls command)
AProcess.Execute;
// Create a stream object to store the generated output in. This could
// also be a file stream to directly save the output to disk.
OutputStream := TMemoryStream.Create;
// All generated output from AProcess is read in a loop until no more data is available
repeat
// Get the new data from the process to a maximum of the buffer size that was allocated.
// Note that all read(...) calls will block except for the last one, which returns 0 (zero).
BytesRead := AProcess.Output.Read(Buffer, BUF_SIZE);
// Add the bytes that were read to the stream for later usage
OutputStream.Write(Buffer, BytesRead)
until BytesRead = 0; // Stop if no more data is available
// The process has finished so it can be cleaned up
AProcess.Free;
// Now that all data has been read it can be used; for example to save it to a file on disk
with TFileStream.Create('output.txt', fmCreate) do
begin
OutputStream.Position := 0; // Required to make sure all data is copied from the start
CopyFrom(OutputStream, OutputStream.Size);
Free
end;
// Or the data can be shown on screen
with TStringList.Create do
begin
OutputStream.Position := 0; // Required to make sure all data is copied from the start
LoadFromStream(OutputStream);
writeln(Text);
writeln('--- Number of lines = ', Count, '----');
Free
end;
// Clean up
OutputStream.Free;
end.
将代码存到文件里,比如起名test.fpc, 然后编译并执行:
fpc test.fpc
./test
执行后输出:
./test
total 3760
43907011 16 -rw-r--r-- 1 skywalk staff 6208 8 9 22:01 test.o
43906993 8 -rw-r--r-- 1 skywalk staff 3157 8 9 22:01 test.fpc
43907017 3736 -rwxr-xr-x 1 skywalk staff 1911744 8 9 22:02 test
1447254 0 drwxr-xr-x 47 skywalk staff 1504 8 9 22:01 ..
43906897 0 drwxr-xr-x 5 skywalk staff 160 8 9 22:02 .
--- Number of lines = 6----
可以看到成功的调用了
将命令设为/bin/ps ,也成功了。
AProcess.Executable := '/bin/ps';
但是测试/usr/bin/top没有成功,看代码里,需要输出完毕才能处理,但是像top这样永远在输出的,这段代码就适合了。
Using input and output of a TProcess
See processdemo example in the Lazarus-CCR SVN.
Hints on the use of TProcess关于TProcess的使用提示
当创建跨平台应用的时候,可以使用"{$IFDEF}" 和 "{$ENDIF}"来设定特定操作系统的可执行命令。
Example:
{...} AProcess := TProcess.Create(nil) {$IFDEF WIN32} AProcess.Executable := 'calc.exe'; {$ENDIF} {$IFDEF LINUX} AProcess.Executable := FindDefaultExecutablePath('kcalc'); {$ENDIF} AProcess.Execute; {...}
macOS show application bundle in foreground在macOS中以前台方式显示应用程序包
可以通过TProcess启动应用程序包内的可执行文件来启动该应用程序包。例如:
AProcess.Executable:='/Applications/iCal.app/Contents/MacOS/iCal';
这将启动日历应用,但窗口可能会出现在当前应用之后。为了将应用程序置于前台,你可以使用open
工具并带上-n
参数:
AProcess.Executable:='/usr/bin/open'; AProcess.Parameters.Add('-n'); AProcess.Parameters.Add('-a'); // optional: specifies the application to use; only searches the Application directories AProcess.Parameters.Add('-W'); // optional: open waits until the applications it opens (or were already open) have exited AProcess.Parameters.Add('Pages.app'); // including .app is optional
如果你的应用程序需要参数,你可以在--args
参数之后传递所有参数,这些参数将被传递给应用程序:
AProcess.Parameters.Add('--args'); AProcess.Parameters.Add('argument1'); AProcess.Parameters.Add('argument2');
See also: macOS open command.
Run detached program运行分离的程序
通常情况下,由你的应用程序启动的程序是一个子进程,当你的应用程序被终止时,这个子进程也会被终止。当你想要运行一个独立运行的程序时,可以使用以下方式:
var Process: TProcess; I: Integer; begin Process := TProcess.Create(nil); try Process.InheritHandles := False; Process.Options := []; Process.ShowWindow := swoShow; // Copy default environment variables including DISPLAY variable for GUI application to work for I := 1 to GetEnvironmentVariableCount do Process.Environment.Add(GetEnvironmentString(I)); Process.Executable := '/usr/bin/gedit'; Process.Execute; finally Process.Free; end; end;
调试
Redirecting input and output and running under root这个例子在mac没通过
在输入密码后,程序退出,无显示 。应该是passwd密码处理那块没兼容。
另外里面ls的路径Mac下也没有。