procedure MoreTest_TProcess_Executable_Parameters_ReadOnlyIfAvailable; // Try to mimic Process.internalRuncommand
const BUF_SIZE = 65536; // Read at most BUF_SIZE bytes at one time
var
Proc: TProcess;
OutMemStream, ErrMemStream: TMemoryStream;
OutNumBytes, ErrNumBytes: LongInt;
OutLines, ErrLines: TStrings;
Available, BytesRead: LongInt;
begin
Proc := TProcess.Create(nil);
try
//Proc.Executable := '/home/vagrant/test.sh';
//(*
Proc.Executable := '/bin/bash';
Proc.Parameters.Add('-c');
Proc.Parameters.Add('nohup ~/script1 & bg_id=$! ; disown -a ; while true ; do if ! ps -p $bg_id > /dev/null 2>&1 ; then echo "script1 terminated" ; break; fi ; str=$(ps aux | grep [^]]script2) ; BashRegex=''^[[:alnum:]_]+\s+([[:alnum:]_]+)'' ; if [[ $str =~ $BashRegex ]] ; then for (( i=1 ; i<${#BASH_REMATCH[@]} ; i++)) ; do echo ${BASH_REMATCH[$i]} ; done ; break ; else sleep 5 ; fi ; done');
//*)
//Proc.Options := [poUsePipes, poWaitOnExit]; // Also works...
Proc.Options := [poUsePipes];
Proc.Execute;
OutMemStream := nil;
ErrMemStream := nil;
OutLines := nil;
ErrLines := nil;
try
OutMemStream := TMemoryStream.Create;
ErrMemStream := TMemoryStream.Create;
OutLines := TStringList.Create;
ErrLines := TStringList.Create;
OutNumBytes := 0;
ErrNumBytes := 0;
while Proc.Active or (Proc.Output.NumBytesAvailable > 0) or (Assigned(Proc.Stderr) and (Proc.Stderr.NumBytesAvailable > 0)) do
begin
Available := Proc.Output.NumBytesAvailable;
while Available > 0 do // Only read if data from corresponding stream is available. Otherwise, read blocks on linux
begin
if Available > BUF_SIZE then
begin
Available := BUF_SIZE; // Read at most BUF_SIZE bytes at one time
end;
OutMemStream.Size := OutNumBytes + Available; // Allocate storage in advance
BytesRead := Proc.Output.Read((OutMemStream.Memory + OutNumBytes)^, Available); // Read data into stream storage
Assert(BytesRead = Available);
if BytesRead > 0 then
begin
Inc(OutNumBytes, BytesRead);
end;
Available := Proc.Output.NumBytesAvailable;
end;
if Assigned(Proc.Stderr) then // Check for assigned(P.stderr) to prevent AV if poStderrToOutput in p.Options.
begin
Available := Proc.Stderr.NumBytesAvailable;
while Available > 0 do
begin
if Available > BUF_SIZE then
begin
Available := BUF_SIZE; // Read at most BUF_SIZE bytes at one time
end;
ErrMemStream.Size := ErrNumBytes + Available; // Allocate storage in advance
BytesRead := Proc.StdErr.Read((ErrMemStream.Memory + ErrNumBytes)^, Available); // Read data into stream storage
Assert(BytesRead = Available);
if BytesRead > 0 then
begin
Inc(ErrNumBytes, BytesRead);
end;
Available := Proc.Stderr.NumBytesAvailable;
end;
end;
end;
OutMemStream.Size := OutNumBytes;
ErrMemStream.Size := ErrNumBytes;
OutMemStream.Position := 0;
OutLines.LoadFromStream(OutMemStream);
ErrMemStream.Position := 0;
ErrLines.LoadFromStream(ErrMemStream);
Writeln('##### Out #####' + sLineBreak + OutLines.Text + sLineBreak + '##### Err #####' + sLineBreak + ErrLines.Text);
finally
OutMemStream.Free;
ErrMemStream.Free;
OutLines.Free;
ErrLines.Free;
end;
finally
Proc.Free;
end;
end;