Thanks for the response Sam707, unfortunately if you try that you'll see the problem. You can do as you say (which is almost the code I posted above) and you'll get the cmd line output but not the prompts and the input pipe to TProcess won't send commands to the prompt.
Here's the full code of my simple shell app that does what you suggest but doesn't meet my tests (e.g. try running "ftp" or similar with this kind of approach).
unit ufrmSimpleShell;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, process, FileUtil, Forms, Controls, Graphics, Dialogs,
StdCtrls, ExtCtrls, AsyncProcess, LCLType;
type
{ TfrmShell }
TfrmShell = class(TForm)
btnExec : TButton;
edtInput : TEdit;
FProcess : TAsyncProcess;
mmLog : TMemo;
procedure btnExecClick(Sender : TObject);
procedure edtInputKeyUp(Sender : TObject; var Key : Word;
Shift : TShiftState);
procedure FormClose(Sender : TObject; var CloseAction : TCloseAction);
procedure FormCreate(Sender : TObject);
procedure FProcessReadData(Sender : TObject);
procedure FProcessTerminate(Sender : TObject);
private
function ReadOutput(const aproc : TAsyncProcess) : string;
procedure Log(const s : string);
procedure Log(Const Fmt : String; const Args : Array of const);
public
{ public declarations }
end;
var
frmShell : TfrmShell;
implementation
uses LCLProc;
{$R *.lfm}
{ TfrmShell }
procedure TfrmShell.FormCreate(Sender : TObject);
begin
FProcess.Executable := '/bin/sh';
FProcess.Parameters.Add('-i');
FLastRunning := true;
FProcess.Execute;
FProcessReadData(Sender);
end;
procedure TfrmShell.btnExecClick(Sender : TObject);
var
inputstr : TCaption;
begin
inputstr := edtInput.Text;
Log('Sending input: "%s"',[inputstr]);
inputstr := inputstr + #10;
FProcess.Input.Write(inputstr[1],Length(inputstr));
end;
procedure TfrmShell.edtInputKeyUp(Sender : TObject; var Key : Word;
Shift : TShiftState);
begin
if Key = VK_RETURN then
btnExecClick(Sender);
end;
procedure TfrmShell.FormClose(Sender : TObject; var CloseAction : TCloseAction);
begin
FProcess.Terminate(0);
end;
procedure TfrmShell.FProcessReadData(Sender : TObject);
var newOutput : string;
begin
newOutput := ReadOutput(FProcess);
if newOutput <> '' then
Log(newOutput);
end;
procedure TfrmShell.FProcessTerminate(Sender : TObject);
begin
Log('Process Terminate');
end;
function TfrmShell.ReadOutput(const aproc : TAsyncProcess) : string;
var tempStrings : TStringList;
begin
tempStrings := TStringList.Create;
try
if assigned(aproc.Output) then
tempStrings.LoadFromStream(aproc.Output);
Result := tempStrings.Text;
finally
tempStrings.Free;
end;
end;
procedure TfrmShell.Log(const s : string);
begin
mmLog.Lines.Add(s);
end;
procedure TfrmShell.Log(const Fmt : String; const Args : array of const);
begin
Log(Format(Fmt,Args));
end;
end.
This kind of thing can't even see the prompt lines ending % or > or whatever as they're not part of the output piped to the stream, they go straight to the outer console if there is one.