Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2011-07

Re: Running programs with output redirection

16 messages · 8 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Graeme Geldenhuys
to Hans-Peter Diettrich: There seems to exist an issue with (output) redirection, when I try to run an external…
Hans-Peter Diettrich wrote
Does there exist a simple way to run "diff", and to redirect its output into an file? A batch file? Platform independence would be nice, of course.

Execute diff with the two parameters via TProcess. Read the output as normal, and simply write that output to a text file using TFileStream, TStringList etc..

eg:
  p := TProcess.Create(nil);
  p.Options := [poUsePipes, poStdErrToOutPut];
  ....
  p.Execute
  ...
    SetLength(Buf,BufSize);
    repeat
      if (p.Outputnil) then
      begin
        Count:=p.Output.Read(Buf[1],Length(Buf));
        // add Buf to a TFileStream, TStringList etc.
      ...
     until Count=0;
Regards,   - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://fpgui.sourceforge.net

Reply by email

Hans-Peter Diettrich

There seems to exist an issue with (output) redirection, when I try to run an external program from code. What I want to achieve is this:

In a Win32 console I can run

diff -r dir1 dir2 > diff.txt

When I use e.g. Exec('diff', args), diff complains about an excess argument, it works when "> diff.txt" is removed. With other functions I had less luck (ExecuteProcess, CreateProcess...), no I assume that output redirection is a shell feature, not available in direct invocation of an external program. Right?

Does there exist a simple way to run "diff", and to redirect its output into an file? A batch file? Platform independence would be nice, of course.

DoDi

Reply by email

Andrew Haines
to Hans-Peter Diettrich
Hans-Peter Diettrich wrote 19 lines
There seems to exist an issue with (output) redirection, when I try to run an external program from code. What I want to achieve is this: In a Win32 console I can run >diff -r dir1 dir2 > diff.txt When I use e.g. Exec('diff', args), diff complains about an excess argument, it works when "> diff.txt" is removed. With other functions I had less luck (ExecuteProcess, CreateProcess...), no output at all. Now I assume that output redirection is a shell feature, not available in direct invocation of an external program. Right? Does there exist a simple way to run "diff", and to redirect its output into an file? A batch file? Platform independence would be nice, of course. DoDi _____

The best way I know is described here:
http://wiki.lazarus.freepascal.org/Executing_External_Programs#How_to_redirect_output_with_TProcess

something like the following (not tested)

function RunCommandAndDirectOutput(ACommand, AArgs, AOutName: String):
Integer;
var
 proc: TProcess;
 data: TFileStream;
 buffer: array [0..511] of byte;
 count: Integer;
begin
  proc := TProcess.Create(nil);
  proc.commandline := ACommand + ' ' + AArgs;
  proc.options := [pousepipes];
  data := TFileStream.Create(AOutName, fmcreate or fmwrite);
  proc.Execute;
  while proc.running or proc.output.numbytesavailable > 0 do
  begin
    count := proc.output.numbytesavailable;
    if count > 512 then
      count := 512;
    count := proc.output.read(buffer, count);
    data.write(buffer, count);
  end;
  Result := Proc.ExitStatus;
  proc.free;
  data.free;
end;

usage:

RunCommandAndDirectOutput('diff', '-r dir1 dir2', 'diff.txt');

Regards,

Andrew Haines

Reply by email

Sven Barth
to Hans-Peter Diettrich: There seems to exist an issue with (output) redirection, when I try to run an external…
Hans-Peter Diettrich wrote 13 lines
There seems to exist an issue with (output) redirection, when I try to run an external program from code. What I want to achieve is this: In a Win32 console I can run >diff -r dir1 dir2 > diff.txt When I use e.g. Exec('diff', args), diff complains about an excess argument, it works when "> diff.txt" is removed. With other functions I had less luck (ExecuteProcess, CreateProcess...), no output at all. Now I assume that output redirection is a shell feature, not available in direct invocation of an external program. Right?

In addition to the solution given by Andrew (namely using TProcess), I'd like to confirm that input/output redirection using ">", "<", "|", etc. is indeed a feature of the shell (be it DOS shell, NT command line or bash).
To use input/output redirection yourself in a program you need to point the Stdin, Stdout and/or Stderr handles of the called program to the source or sink you desire. For Windows that means passing handles for StdIn, StdOut and StdErr to CreateProcess. I don't know the procedure on Linux, but there the same basic concept applies. All this is encapsulated by TProcess.

Regards,
Sven

Reply by email

Ludo Brands
to Hans-Peter Diettrich: There seems to exist an issue with (output) redirection, when I try to run an external…
Show quoted text 16 lines
There seems to exist an issue with (output) redirection, when I try to run an external program from code. What I want to achieve is this: In a Win32 console I can run >diff -r dir1 dir2 > diff.txt When I use e.g. Exec('diff', args), diff complains about an excess argument, it works when "> diff.txt" is removed. With other functions I had less luck (ExecuteProcess, CreateProcess...), no output at all. Now I assume that output redirection is a shell feature, not available in direct invocation of an external program. Right?

Redirection is indeed a shell function.

Show quoted text 5 lines
Does there exist a simple way to run "diff", and to redirect its output into an file? A batch file? Platform independence would be nice, of course.

Start the shell instead of diff:

  exec('cmd','/c diff -r dir1 dir2 > diff.txt');

The /c tells the shell to execute the command and exit immediately.

Ludo

Reply by email

Ludo Brands
to Ludo Brands
Show quoted text 12 lines
> Does there exist a simple way to run "diff", and to redirect > its output > into an file? A batch file? Platform independence would be > nice, of course. > Start the shell instead of diff: exec('cmd','/c diff -r dir1 dir2 > diff.txt'); The /c tells the shell to execute the command and exit immediately.

The above solution will show briefly the cmd window, the time of exexcuting the diff. If you want to get rid of these popups you can use the following alternative:

  ShellExecute(0, nil, 'cmd.exe', '/c diff -r dir1 dir2 > diff.txt', nil,
0);

You need to add shellapi to the uses clause. Note that ShellExecute returns immediately and the new shell runs in the background, even when the program stops. The new parent of the shell process is Explorer. Exec returns when the shell ends.

This is all windows though.

Ludo

Reply by email

Ludo Brands
to Ludo Brands
This is all windows though.

Cross platform solution:

Uses process
...
  p:=TProcess.Create(nil);
{$IFDEF WIN32}
  p.CommandLine := 'cmd /c diff -r dir1 dir2 > diff.txt';
{$ENDIF}
{$IFDEF LINUX}
  p.CommandLine := 'bash -c "diff -r dir1 dir2 > diff.txt"';
{$ENDIF}
  p.Execute;
...

Ludo

Reply by email

Hans-Peter Diettrich
to Andrew Haines: The best way I know is described here: http://wiki.lazarus.freepascal.org/Executing_Extern…

Thanks for the link, I didn't know before that redirecting is such a big issue.

RunCommandAndDirectOutput('diff', '-r dir1 dir2', 'diff.txt');

Can I tell diff to only compare *.xml files?

I want to track modifications in the FPC/Lazarus docs files...

DoDi

Reply by email

Mark Morgan Lloyd
to Ludo Brands: Cross platform solution: Uses process ... p:=TProcess.Create(nil); {$IFDEF WIN32}…
Ludo Brands wrote 16 lines
> This is all windows though. > Cross platform solution: Uses process ... p:=TProcess.Create(nil); {$IFDEF WIN32} p.CommandLine := 'cmd /c diff -r dir1 dir2 > diff.txt'; {$ENDIF} {$IFDEF LINUX} p.CommandLine := 'bash -c "diff -r dir1 dir2 > diff.txt"'; {$ENDIF} p.Execute;

Might be safer to refer to sh rather than bash in this context, since Debian and Ubuntu are moving from Bash to Dash with sh being an appropriate symlink.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Hans-Peter Diettrich
to Ludo Brands: Redirection is indeed a shell function. Start the shell instead of diff: exec('cmd','/c…
Show quoted text 5 lines
Start the shell instead of diff: exec('cmd','/c diff -r dir1 dir2 > diff.txt'); The /c tells the shell to execute the command and exit immediately.

Thanks, this comes close to what I had in mind :-)

But it looks quite platform dependent, like my other idea of invoking a shell script. Now I'll give TProcess and pipes an try...

DoDi

Reply by email

Hans-Peter Diettrich
to Ludo Brands: Cross platform solution: Uses process ... p:=TProcess.Create(nil); {$IFDEF WIN32}…
Show quoted text 13 lines
Cross platform solution: Uses process ... p:=TProcess.Create(nil); {$IFDEF WIN32} p.CommandLine := 'cmd /c diff -r dir1 dir2 > diff.txt'; {$ENDIF} {$IFDEF LINUX} p.CommandLine := 'bash -c "diff -r dir1 dir2 > diff.txt"'; {$ENDIF} p.Execute;

Looks like this could be added to the wiki, as another solution. Unfortunately it won't work on other platforms (Mac...).

DoDi

Reply by email

Ludo Brands
to Hans-Peter Diettrich
Show quoted text 16 lines
> Cross platform solution: > > Uses process > > ... > p:=TProcess.Create(nil); > {$IFDEF WIN32} > p.CommandLine := 'cmd /c diff -r dir1 dir2 > diff.txt'; {$ENDIF} > {$IFDEF LINUX} > p.CommandLine := 'bash -c "diff -r dir1 dir2 > diff.txt"'; > {$ENDIF} > p.Execute; Looks like this could be added to the wiki, as another solution. Unfortunately it won't work on other platforms (Mac...).

Should have been {$IFDEF UNIX} since it works also on Darwin, Solaris, etc.

Ludo

Reply by email

Ludo Brands
to Mark Morgan Lloyd: Might be safer to refer to sh rather than bash in this context, since Debian and Ubuntu…
Show quoted text 5 lines
Might be safer to refer to sh rather than bash in this context, since Debian and Ubuntu are moving from Bash to Dash with sh being an appropriate symlink.

For this simple example it won't matter but for more complex ones using certain shell specifics it is a must to launch the correct shell. The sh symlink can point to anything.

Ludo

Reply by email

Jonas Maebe
to Ludo Brands
Ludo Brands wrote
For this simple example it won't matter but for more complex ones using certain shell specifics it is a must to launch the correct shell. The sh symlink can point to anything.

Yes, but bash may not even exist.

Jonas

Reply by email

David W Noon
to Mark Morgan Lloyd: Might be safer to refer to sh rather than bash in this context, since Debian and Ubuntu…

On Sun, 17 Jul 2011 09:51:12 +0000, Mark Morgan Lloyd wrote about Re: RE : RE : RE : [fpc-devel] Running programs with output redirection:

Ludo Brands wrote:

[snip]

Show quoted text 8 lines
> {$IFDEF LINUX} > p.CommandLine := 'bash -c "diff -r dir1 dir2 > diff.txt"'; > {$ENDIF} > p.Execute; Might be safer to refer to sh rather than bash in this context, since Debian and Ubuntu are moving from Bash to Dash with sh being an appropriate symlink.

Even better would be to use the SHELL environment variable. This is established by the login shell and reflects each user's default shell, as per /etc/passwd.

Regards, Dave [RLU #314465] ======================================================================= (David W Noon) =======================================================================

Reply by email

Andrew Haines
to Hans-Peter Diettrich: Thanks for the link, I didn't know before that redirecting is such a big issue. Can I…
Hans-Peter Diettrich wrote 16 lines
Andrew Haines schrieb: > The best way I know is described here: > http://wiki.lazarus.freepascal.org/Executing_External_Programs#How_to_redirect_output_with_TProcess > Thanks for the link, I didn't know before that redirecting is such a big issue. > RunCommandAndDirectOutput('diff', '-r dir1 dir2', 'diff.txt'); Can I tell diff to only compare *.xml files? I want to track modifications in the FPC/Lazarus docs files...

I don't know if diff can be made to only match files against a pattern but it can _ignore_ files matching a pattern. Anyway I made a program that can do what you want mostly. It may be useful to you or not.

Also the TProcess example is slightly simpler.

Regards,

Andrew Haines

Reply by email