Recent

Author Topic: SOLVED- Tprocess Executable (Commandline Depreciated)  (Read 20705 times)

wjackson153

  • Sr. Member
  • ****
  • Posts: 267
SOLVED- Tprocess Executable (Commandline Depreciated)
« on: January 23, 2013, 04:55:53 am »
This has been modified from the original posting:

if we follow this link and read under Tprocess
  http://wiki.lazarus.freepascal.org/Executing_External_Programs#SysUtils.ExecuteProcess

      it states the following  :

Quote
TProcess reference

Important notes:

    TProcess is not a terminal/shell! You cannot directly execute scripts or redirect output using operators like "|", ">", "<", "&" etc.
   

I will mention using my method I can execute shell scripts or redirect illegal characters as parameters.


Lets assume you are a linux user  like me and your wanting to use
lazarus to send commands from your application to a console and report
the output from the command  you sent.

We can do this by using Tprocess  and its quite simple really :)

Code: [Select]
Procedure TForm1.Button1Click(Sender: TObject);
var
    hprocess: TProcess;
    sPass: String;
Begin

   sPass := 'baconisgreat';
   hProcess := TProcess.Create(nil);
 
   hProcess.Executable := '/bin/sh';
   hprocess.Parameters.Add('-c');              // This is needed or you will get errors from stderr
   // mental note any paremeters that are passed after the first parameter needs to be passed
  //  as a single line argument,  notice in the below parameter  ping -c  yes there is yet another
  //  switch that wiki refers to as being added as one parameter however if you do your program
  //  will not work.

   
  // Now we can pass illegal chars just as if you typed them on terminal just like so
  hprocess.Parameters.Add('ifconfig wlan0 | grep ' +  QuotedStr('inet addr:') + ' | cut -d: -f2');
 
  //  Below are some examples of its use
  //  hprocess.Parameters.Add('ping -c 3 www.google.com'); // Ping google 3 times
  //  hprocess.Parameters.Add('glxinfo | grep direct'); // Determine if direct rendering is enabled
  //  hprocess.Parameters.Add('cat /etc/isssue');        // Determine linux version
 
  // some linux commands need elevated privlege to do so you could use the following
   //hprocess.Parameters.add('echo ' + sPass  + ' | sudo -S fdisk -l');
 
   hProcess.Options := hProcess.Options + [poWaitOnExit, poUsePipes];  //  Just what it says
   hProcess.Execute;         // Execute the command with parameters

   memo1.Lines.LoadFromStream(hprocess.Output); // Output from command issued from above
   memo2.Lines.LoadFromStream(hProcess.Stderr);  // Reported errors if any
   hProcess.Free;                                                      // Finally we free created instance

 end;                   

Using the above syntax you could easily send linux commands to an invisible enviroment
from FPC or Lazarus and read the output into a memobox  and store chunks to a datatype
without ever revealing a console to the user.


I hope that this has helped anyone that needs functionality such as this in his/her
application.  :)

If you have found this useful as I have  please send a greeting, because many will say
that this has been covered on the wiki  however I will tell you I have read the wiki, and tons
of external sites and they way they explain how to use Tprocess executable with params
is very misleading, and doumentation else where have not covered this topic in depth as I
have.

There were a few translations I found that referred to using tStrings and delimedtext
but once again if you use those methods then you are reverting to the old way of doing this
with Tprocess commandline  which is now depreciated. Though it works for the time being.

This has been a long a tedius journey of days on end reading, trial and error, and and final
conclustion has taught me that if first you don't succeed, try, try, try till you do. :)

All comments are welcome, as I would like to know if this has been a huge issue for linux
users other then myself.
« Last Edit: January 24, 2013, 03:29:49 am by wjackson153 »
Lazarus 1.1 r39490 CT FPC 2.7.1 i386-linux KDE
Linux Mint 14 KDE 4

CaptBill

  • Sr. Member
  • ****
  • Posts: 435
Re: Tprocess Executable Help
« Reply #1 on: January 23, 2013, 06:49:38 am »
The Wiki has a good article on TProcess.

I think what you want is there.

http://wiki.lazarus.freepascal.org/Executing_External_Programs

wjackson153

  • Sr. Member
  • ****
  • Posts: 267
Re: Tprocess Executable Help
« Reply #2 on: January 23, 2013, 06:58:01 am »
No that is not what I want

Commandline is depreciated

So want to learn how to do the same thing as I could do with commandline
but with executable method, every example I have tried either locks up
or does nothing.

My goal is to use Tprocess  with executable and params passed to the executed application
Lazarus 1.1 r39490 CT FPC 2.7.1 i386-linux KDE
Linux Mint 14 KDE 4

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12718
  • FPC developer.
Re: Tprocess Executable Help
« Reply #3 on: January 23, 2013, 01:33:46 pm »
Tprocess works fine, I use it daily.

So the problem is something specific to the lxterminal binary. What does lxterminal expect that is so special?

wjackson153

  • Sr. Member
  • ****
  • Posts: 267
Re: Tprocess Executable Help
« Reply #4 on: January 23, 2013, 07:12:56 pm »
using executable with  .parameters.add('param1') .parameters.add('param2')etc


ok lets assume the following:

I have form with 2 memobox  1 catches stderr the other catches the output

I have a command button on the form

Procedure TForm1.Button1Click(Sender: TObject);
var
   hprocess: TProcess;

Begin
  hProcess := TProcess.Create(nil);

 // hProcess.CommandLine := 'sh -c "echo baconisgreat | sudo -S fdisk -l"';

 // the above line works, however that syntax is depreciated, I would like to
 // convert that line into the new standard using Executable with parameters.


  hProcess.Executable := '/bin/sh';
  hprocess.Parameters.Add('-c');
  hprocess.Parameters.add('"');
  hprocess.Parameters.add('echo');
  hprocess.Parameters.Add('baconisgreat');  // this is a tempory sudo password for testing purpose
  hprocess.Parameters.Add('|');
  hprocess.parameters.Add('sudo');
  hprocess.Parameters.Add('-S');
  hprocess.Parameters.Add('fdisk');
  hprocess.Parameters.Add('-l"');
  hprocess.Parameters.add('"');

  hProcess.Options := hProcess.Options + [poWaitOnExit, poUsePipes];
  hProcess.Execute;
  memo1.Lines.LoadFromStream(hprocess.Output);
  memo2.Lines.LoadFromStream(hProcess.Stderr);
  hProcess.Free;

 end;     

at this point stderr is reporting Syntax error: Unterminated quoted string
but yet the parameters are identical to the depreciated commandline .
Lazarus 1.1 r39490 CT FPC 2.7.1 i386-linux KDE
Linux Mint 14 KDE 4

wjackson153

  • Sr. Member
  • ****
  • Posts: 267
Re: Tprocess Executable Help
« Reply #5 on: January 23, 2013, 08:56:04 pm »
Ok first I would like to thank everyone that has given me instruction or direction, but I will state
none of the instruction or links that were offered give me a viable method.  After Many hours
of trial and error I decided to try something that was not obvious at first.

Because  on fpc wiki it says to pass arguments by 1
so I assumed they meant something like so:

   hprocess.Parameters.Add('-c');
   hprocess.Parameters.add('echo);
   hprocess.Parameters.Add('sPass');
   hprocess.Parameters.Add('|');
 
I will not go through the entire list of arguments to be passed but you get the idea.

I achieved the above translation as such because this:

Quote
Commandline arguments should be specified one per item in Parameters: each item in Parameters will be passed as a separate command-line item. It is therefor not necessery to quote whitespace in the items. As a consequence, it is not allowed to specify multiple command-line parameters in 1 item in the stringlist. If a command needs 2 options -t and -s, the following is not correct:

With Parameters do
  begin
  add('-t -s');
  end;

Instead, the code should read:

With Parameters do
  begin
  add('-t');
  Add('-s');
  end;

Does not the above instructions or one argument per parameter just mean 1 ????

I conclude that the above had me and many others racking our heads as two why
we could translate a working syntax according to the old syntax  that of witch you
will see below uses multiple aguments into one line. That the above says will not work
bet yet it works flawlessly and does not complain about command line depreciated.

The above code should read and I quote,  only switches ie  -c -l   so forth
need to be one per parameter,  though arguments may be passed as one parameter

because the below example will not work.

   hProcess.Executable := '/bin/sh';
   hprocess.Parameters.add('-c  echo ' + sPass  + ' | sudo -S fdisk -l');
   
   however if you pass it as such

   hProcess.Executable := '/bin/sh';
   hprocess.Parameters.Add('-c');
   hprocess.Parameters.add('echo ' + sPass  + ' | sudo -S fdisk -l');
 
   It will compile and work as it was meant too. because -c is a switch or option
  and 'echo ' + sPass  + ' | sudo -S fdisk -l' is multiple aguments that are to be
  passed to sh shell

Complete working example below
 
Code: [Select]
Procedure TForm1.Button1Click(Sender: TObject);
var
    hprocess: TProcess;
    sPass: String;
Begin

   sPass := 'baconisgreat';  // sudo password for your linux box
   hProcess := TProcess.Create(nil);

  //hProcess.CommandLine := 'sh -c "echo baconisgreat | sudo -S fdisk -l"';

 // the above line works, however that syntax is depreciated, I would like to
 // convert that line into the new standard using Executable with parameters.

   //   Conversion Begin
   hProcess.Executable := '/bin/sh';
   hprocess.Parameters.Add('-c');
   hprocess.Parameters.add('echo ' + sPass  + ' | sudo -S fdisk -l');  // Hmm multiple argument on
  // one line??? But this is how to make it work. But wiki say its not supose to work and that only
 // one argument per parameter.
  // Conversion End

   hProcess.Options := hProcess.Options + [poWaitOnExit, poUsePipes];
   hProcess.Execute;
   memo1.Lines.LoadFromStream(hprocess.Output);
   memo2.Lines.LoadFromStream(hProcess.Stderr);
   hProcess.Free;

 end;     
Lazarus 1.1 r39490 CT FPC 2.7.1 i386-linux KDE
Linux Mint 14 KDE 4

wjackson153

  • Sr. Member
  • ****
  • Posts: 267
Re: SOLVED- Tprocess Executable (Commandline Depreciated)
« Reply #6 on: January 23, 2013, 11:05:57 pm »
Post has been updated for original post.
and all changes have been reflected to the starting post.


Thanks.


Lazarus 1.1 r39490 CT FPC 2.7.1 i386-linux KDE
Linux Mint 14 KDE 4

CaptBill

  • Sr. Member
  • ****
  • Posts: 435
Re: SOLVED- Tprocess Executable (Commandline Depreciated)
« Reply #7 on: January 24, 2013, 12:15:20 am »
So you are saying we can now use the TProcess like this...?

Code: [Select]
ShellExecute('firstcommand.exe | secondcommand.exe');
This is good to know. I didn't realize commandline was deprecated. You should update the wiki for TProcess with a simple demo. TProcess is a great "code re-use" class.

Thanks for fleshing out the details.

Also, a note pointing to the old-style or depricated methods, would be a good idea.

wjackson153

  • Sr. Member
  • ****
  • Posts: 267
Re: SOLVED- Tprocess Executable (Commandline Depreciated)
« Reply #8 on: January 24, 2013, 01:23:29 am »
Not exactly you don't even need to call on ShellExecute()
Infact that is a whole another beast in itself


Code: [Select]
Procedure TForm1.Button1Click(Sender: TObject);
uses
process;

var
    hprocess: TProcess;
   Begin
 
   hProcess := TProcess.Create(nil);
   hProcess.Executable := '/bin/sh';
   hprocess.Parameters.Add('-c');             
     
  hprocess.Parameters.Add('glxinfo | grep direct');
  // here we can pipe additional commands in this case im running the program glxinfo
  // and using grep direct  to determine the current status for direct rending is enabled on
  // my linux distro.  Just as if I were to type it on a console  glxinfo | grep direct and press enter

  // when using pipes to redirect it has to be related to the first launched application
  // however we can launch multiple programs and have them report output back to our program
 // but it can not be done like so :
    // hprocess.Parameters.Add('glxinfo | whereis fdisk');  //  because only the right side of pipe
    // is read as a command the left side is ignored because it is two different programs being
   // started.  However for unknown reason its only exception is for awk and grep i would only
  //  assume this is because they are native for parsing information from programs ???
 

   hProcess.Options := hProcess.Options + [poWaitOnExit, poUsePipes];
   hProcess.Execute;     

   memo1.Lines.LoadFromStream(hprocess.Output);
   memo2.Lines.LoadFromStream(hProcess.Stderr); 
   hProcess.Free;                                                   

 end;
 


I can only sugguest the reader if he/she is intrested that they start a new project
and follow my instructions above to see exactly how it works.  In doing so this
topic will be less confussing for those that are not familar with what  my purpose was.

But to keep it simple. I needed a way to start a app from my linux box, but not only that
I wanted the output concealed from the user in otherwords not to open a external console.
but report the output to a memobox where I can work with it from within my application.
in this way I can comunicate with the 3rd party application and know exactly when to
send the next command, since I my output is stored to a string var I can manipulate  the
output as its rendered to my application.

Ok lets assume you have your program downloading using wget the file will take some time
so I can report the percentage to a progressbar and update and know exactly when the down
load is completed.  At this point so not to create much lag I can start the next download rather
then launching 30 downloads all at once.  This is one example.

Next assume we want to make a gui for a CLI app that we use reguarly, in this example I will
use the ever so popular tar command.  Once again I have sent the arguments to the hidded console
and my app is waiting for output from the tar process that we started. I know exactly when process
has completed. So I can start the next process, without bogging down the users pc.


I hope this has shed some light on its purpose :)


                 
Lazarus 1.1 r39490 CT FPC 2.7.1 i386-linux KDE
Linux Mint 14 KDE 4

CaptBill

  • Sr. Member
  • ****
  • Posts: 435
Re: SOLVED- Tprocess Executable (Commandline Depreciated)
« Reply #9 on: January 24, 2013, 05:32:21 am »
One question... have you figured out a way to scroll correctly? I was using the same idea you have, using svn and git, spitting the output to a tmemo. Never could get it to scroll automatically, only manually.
« Last Edit: January 24, 2013, 05:34:17 am by CaptBill »

wjackson153

  • Sr. Member
  • ****
  • Posts: 267
Re: SOLVED- Tprocess Executable (Commandline Depreciated)
« Reply #10 on: January 24, 2013, 05:51:54 am »
You could try something like this

Procedure TForm1.Memo1Change(Sender: TObject);
var
    i: Integer;
Begin
     for i := 0 to memo1.Lines.count - 1 do
     begin
       application.ProcessMessages; 
       Memo1.SelStart := Length(Memo1.Text);
     End;

end;     

Unless you have a huge amount of output being how its in the change event
its possible you don't even need the loop, so you could update the
scrollbar just by calling:

  Memo1.SelStart := Length(Memo1.Text):

 Or do something like:
   

   if not (hProcess.Active = true) or (hProcess.Running = true) then
   begin
   Memo1.SelStart := Length(Memo1.Text);
   end;
   hProcess.Free; 
« Last Edit: January 24, 2013, 09:55:13 pm by wjackson153 »
Lazarus 1.1 r39490 CT FPC 2.7.1 i386-linux KDE
Linux Mint 14 KDE 4

wjackson153

  • Sr. Member
  • ****
  • Posts: 267
Re: SOLVED- Tprocess Executable (Commandline Depreciated)
« Reply #11 on: January 25, 2013, 04:24:14 am »
wiki has been updated per your request  CaptBill

Revisions can be viewed below

http://wiki.lazarus.freepascal.org/Executing_External_Programs#A_Simple_Example
Lazarus 1.1 r39490 CT FPC 2.7.1 i386-linux KDE
Linux Mint 14 KDE 4

 

TinyPortal © 2005-2018