[Lazarus] Run 3 extrenal program, pipeline
Sven Barth
pascaldragon at googlemail.com
Thu Feb 2 15:30:47 CET 2012
Am 02.02.2012 12:00, schrieb xmldom at seznam.cz:
> Hi, I need run 3 external program and redirected output: first | second | third
>
> For example:
> df -hT | grep -v -E 'tmpfs|ecryptfs' | grep 'sda2'
> it gives
> /dev/sda2 ext4 19G 11G 7,6G 58% /
>
> I use this http://wiki.lazarus.freepascal.org/Executing_External_Programs#How_to_redirect_output_with_TProcess sample code. It works fine for first | second.
>
> For three programs I try edit it:
>
>
> function threePipe(inputA, inputB, inputC: string): string;
> var
> FirstProcess, SecondProcess, ThirdProcess: TProcess;
> Buffer: array[0..127] of char;
> ReadCount: Integer;
> ReadSize: Integer;
> begin
> FirstProcess := TProcess.Create(nil);
> SecondProcess := TProcess.Create(nil);
> ThirdProcess := TProcess.Create(nil);
>
> FirstProcess.Options := [poUsePipes];
> SecondProcess.Options := [poUsePipes];
> ThirdProcess.Options := [poUsePipes,poStderrToOutPut];
>
> FirstProcess.CommandLine := inputA;
> SecondProcess.CommandLine := inputB;
> ThirdProcess.CommandLine := inputC;
>
> FirstProcess.Execute;
> SecondProcess.Execute;
> ThirdProcess.Execute;
>
> while FirstProcess.Running or (FirstProcess.Output.NumBytesAvailable> 0) do
> begin
> if FirstProcess.Output.NumBytesAvailable> 0 then
> begin
> ReadSize := FirstProcess.Output.NumBytesAvailable;
> if ReadSize> SizeOf(Buffer) then
> ReadSize := SizeOf(Buffer);
> ReadCount := FirstProcess.Output.Read(Buffer[0], ReadSize);
> SecondProcess.Input.Write(Buffer[0], ReadCount);
> end;
> end;
> SecondProcess.CloseInput;
>
> while SecondProcess.Running or (SecondProcess.Output.NumBytesAvailable> 0) do
> begin
> if SecondProcess.Output.NumBytesAvailable> 0 then
> begin
> ReadSize := SecondProcess.Output.NumBytesAvailable;
> if ReadSize> SizeOf(Buffer) then
> ReadSize := SizeOf(Buffer);
> ReadCount := SecondProcess.Output.Read(Buffer[0], ReadSize);
> ThirdProcess.Input.Write(Buffer[0], ReadCount);
> end;
> end;
> ThirdProcess.CloseInput;
>
>
> while ThirdProcess.Running do
> Sleep(1);
> ReadSize := ThirdProcess.Output.NumBytesAvailable;
> if ReadSize> SizeOf(Buffer) then
> ReadSize := SizeOf(Buffer);
> if ReadSize> 0 then
> begin
> ReadCount := ThirdProcess.Output.Read(Buffer, ReadSize);
> //WriteLn(Copy(Buffer,0, ReadCount));
> end
> else
> WriteLn('grep did not find what we searched for. ', ThirdProcess.ExitStatus);
>
> FirstProcess.Free;
> SecondProcess.Free;
> ThirdProcess.Free;
> threePipe := Copy(Buffer,0, ReadCount);
> end;
>
>
>
> But after i call
> Label1.Caption:=threePipe('df -hT', 'grep -v -E ''tmpfs|ecryptfs''', 'grep ''sda2''');
> function my application end with infinite loop.
>
> Where I do an error?
You need to read from all three processes in one loop as they will block
if they've reached the limit of the output pipe. Try something like this
(pseudo code):
while FirstProcess.Running or SecondProcess.Running or
ThirdProcess.Running do begin
FromFirstToSecond;
FromSecondToThird;
FromThirdToOutput;
end;
FromThirdToOutput; // <= you need to process the leftover output from
the process as well
It might be more complex than the above, but in essence this should do
it (maybe you'll need to play with the buffer sizes, etc).
Regards,
Sven
More information about the Lazarus
mailing list