Recent

Author Topic: How to pipe process using TProcess  (Read 20616 times)

arbelest

  • New Member
  • *
  • Posts: 15
How to pipe process using TProcess
« on: July 01, 2010, 07:04:29 pm »
Is Anybody know how to pipe prosess using Tprocess ?
For example, how to do this command :
   cat /etc/passwd | cut -d ":" -f 1

and also capture that output.
Now i solve this problem using shell, but this solution make my project less compatible with windows.
I have try using TProcess and apply that command, but i think TProcess ignore pipe, just execute cat /etc/passwd

Any suggestion here ?

Leledumbo

  • Hero Member
  • *****
  • Posts: 8836
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: How to pipe process using TProcess
« Reply #1 on: July 01, 2010, 10:58:36 pm »
TProcess is NOT a shell, it doesn't handle redirection via pipe operator, nor <, >, 2> etc. The best way is to call sh (or whatever your shell is) and pipe those string to the process (use the Input property) then read the output (using Output property). This sure is OS, actually shell, specific. You may want to put the platform dependent codes in conditional compilation blocks.

JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4715
  • I like bugs.
Re: How to pipe process using TProcess
« Reply #2 on: July 01, 2010, 11:42:59 pm »
Any suggestion here ?

I would read the file like:
Code: [Select]
StringList.LoadFromFile('/etc/passwd');
and then parse it with pascal code.

Juha
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux 64-bit.

theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1946
Re: How to pipe process using TProcess
« Reply #3 on: July 02, 2010, 12:03:56 am »
I would read the file like:

Yes, it's easy. Look:

Code: [Select]
Var sl: TStringList;
  dpos,i: integer;
Begin
  sl := TStringList.Create;
  Try
    sl.LoadFromFile('/etc/passwd');
    For i:=0 To sl.Count-1 Do
      Begin
        dpos := Pos(':',sl[i]);
        If dpos>0 Then sl[i] := Copy(sl[i],1,dpos-1);
      End;
    Memo1.text := sl.text; //Do something with result
  Finally
    sl.free;
  End;
End;

arbelest

  • New Member
  • *
  • Posts: 15
Re: How to pipe process using TProcess
« Reply #4 on: July 02, 2010, 12:44:16 am »
I would read the file like:
Code: [Select]
StringList.LoadFromFile('/etc/passwd');
and then parse it with pascal code.

Juha


cat /etc/passwd is just an example.
In my project, i have to list available printer, so in shell i can write like this:
    lpstat -a | cut -d " " -f 1

TProcess is NOT a shell, ..

Hmm, so i can't use pipe in TProcess. May be i'll try like this.
1. Create Tprocess an apply lpstat -a as it's command
2. Capture Tprocess output, an then parse like theo's code




theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1946
Re: How to pipe process using TProcess
« Reply #5 on: July 02, 2010, 01:23:25 am »
In my project, i have to list available printer,

You can also do this:
- Add the dependency "Printer4Lazarus" to the project (Dropping a TPrintDialog on the Form does the same).
- then "uses Printers"
then:
  Memo1.lines.assign(Printer.Printers);

Leledumbo

  • Hero Member
  • *****
  • Posts: 8836
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: How to pipe process using TProcess
« Reply #6 on: July 02, 2010, 02:45:34 pm »
Quote
1. Create Tprocess an apply lpstat -a as it's command
2. Capture Tprocess output, an then parse like theo's code
Possible. Or if you like, you can create two TProcess instances and do the piping manually. I mean, pipe the lpstat result to the input property of the other TProcess executing cut, the output of 2nd TProcess is what you're looking for.

arbelest

  • New Member
  • *
  • Posts: 15
Re: How to pipe process using TProcess
« Reply #7 on: July 03, 2010, 03:00:17 am »
Possible. Or if you like, you can create two TProcess instances and do the piping manually. I mean, pipe the lpstat result to the input property of the other TProcess executing cut, the output of 2nd TProcess is what you're looking for.
Yups, i've try this one. But it's not working.
This is all code :
Code: [Select]
program project1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes
  { you can add units after this },
  process;

var lPro0:TProcess;
    lPro1:TProcess;
    lList: TStringList;
    lStr: String;

begin
  lList :=TStringList.Create;
  lPro0 :=TProcess.Create(nil);
  lPro0.Options :=lPro0.Options+[poUsePipes, poStderrToOutPut, poNoConsole];

  // First process for handle lpstat
  lPro0.CommandLine :='lpstat -a';
  lPro0.Execute;
  // Capture it's output
  lList.LoadFromStream(lPro0.Output);
  writeln('lpstat -a output :');
  writeln(lList.Text);

  lPro1 :=TProcess.Create(nil);
  lPro1.Options :=lPro1.Options+[poUsePipes, poStderrToOutPut, poNoConsole, poRunSuspended];
  // Second process for handle cut
  lPro1.CommandLine :='cut -d ":" -f 1';
  lPro1.Execute;

  lStr :=lList.Text;
  lPro1.Input.Write(lStr[1],Length(lStr));

  // capture cut process
  lList.LoadFromStream(lPro1.Output);
  writeln(lList.Text);

  lPro0.Free;
  lPro1.Free;
  lList.Free;
end.           


Output :

Code: [Select]
lpstat -a output :
Deskjet-F2100-series accepting requests since Tue 25 May 2010 10:12:27 AM WIT
HP-LaserJet-P1505 accepting requests since Thu 17 Jun 2010 11:38:58 AM WIT
Hp1020(74) accepting requests since Tue 23 Mar 2010 04:11:03 PM WIT
hp3015(73.6) accepting requests since Sat 17 Apr 2010 11:07:24 AM WIT
PDF accepting requests since Wed 18 Nov 2009 01:19:05 PM WIT
ZTC-TLP2844-Z-200dpi accepting requests since Wed 16 Jun 2010 02:35:58 PM WIT



After "show" lpstat -a out put, my program stop, bu not hang or freeze, it like wating for something.
What wrong in my code ?

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12857
  • FPC developer.
Re: How to pipe process using TProcess
« Reply #8 on: July 05, 2010, 11:55:44 am »
The standard trick is to use /bin/sh -c  "cat /etc/passwd | cut -d ":" -f 1"

but then you run into the problem of nested quotes. This is a bug in TProcess (that it doesn't allow you to specify parameters as an array, omitting the need for quoting in some cases)

Maybe by e.g. escape : in some other way (\: ?) this can be worked around.
« Last Edit: July 05, 2010, 01:30:11 pm by marcov »

Leledumbo

  • Hero Member
  • *****
  • Posts: 8836
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: How to pipe process using TProcess
« Reply #9 on: July 05, 2010, 01:28:31 pm »
Quote
What wrong in my code ?
Just a guess, perhaps you should call Resume for the 2nd process. Execute AFAIK doesn't change Suspended state.

JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4715
  • I like bugs.
Re: How to pipe process using TProcess
« Reply #10 on: July 05, 2010, 03:58:19 pm »
I would still get the output from "lpstat -a" and then parse it using pascal.
Piping is cool with command line tools not really when making a pascal application.
You could have parsed the lines already many times while wondering what is wrong with the pipes.

Juha
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux 64-bit.

arbelest

  • New Member
  • *
  • Posts: 15
Re: How to pipe process using TProcess
« Reply #11 on: July 06, 2010, 05:16:47 am »
I'm not giveup yet, but i'm running out of time.
So i decide to parse manually like Juha or Theo said.

 

TinyPortal © 2005-2018