Sign in Join

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

Mailing lists / fpc-pascal / 2006-10

TProcess questions

18 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

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

Adrian Maier

Hello,

I have several questions about executing external programs with TProcess

1. I need to execute the following command :
psql -q -f /home/am/src/gfaf/hlemit_d.sql -v D1="'1-apr-06'" -v D2="'1-jun-06'"

(it might not be obvious at first sight that there are both " and ' enclosing those dates , because the argument must contain the ' ) .

This command works fine when executed from the bash shell. However, it no longer works when executed from my pascal program (with TProcess). Any idea how should i quote the arguments so that they would be properly treated by TProcess?

2. Where is the TProcess documented on the freepascal website? I had found a FCL.pdf some time ago , but I am unable to find that doc on the freepascal website.

3. The code returned by the called program can be got with TProcess.ExitCode , right ? I have a situation in which a program 1 , but TProcess.ExitCode is 0. Therefore it's impossible to detect the failure.

Cheers,
Adrian Maier

Reply by email

Michael Van Canneyt
to Adrian Maier
Adrian Maier wrote 15 lines
Hello, I have several questions about executing external programs with TProcess 1. I need to execute the following command : psql -q -f /home/am/src/gfaf/hlemit_d.sql -v D1="'1-apr-06'" -v D2="'1-jun-06'" (it might not be obvious at first sight that there are both " and ' enclosing those dates , because the argument must contain the ' ) . This command works fine when executed from the bash shell. However, it no longer works when executed from my pascal program (with TProcess). Any idea how should i quote the arguments so that they would be properly treated by TProcess?
You can't. The following lines (line 107 of unix/process.inc)
     Result:=StringReplace(Result,'"','',[rfReplaceAll]);
     Result:=StringReplace(Result,'''','',[rfReplaceAll]);
Will strip all quotes inside a quoted string.

Obviously, this is a bug.

2. Where is the TProcess documented on the freepascal website? I had found a FCL.pdf some time ago , but I am unable to find that doc on the freepascal website.

It is not documented currently. It's scheduled as the next unit to be documented.

Show quoted text 5 lines
3. The code returned by the called program can be got with TProcess.ExitCode , right ? I have a situation in which a program 1 , but TProcess.ExitCode is 0. Therefore it's impossible to detect the failure.

That can be if the program exited because of a signal.

Michael.

Reply by email

Vincent Snijders
to Michael Van Canneyt
Michael Van Canneyt wrote 10 lines
On Tue, 3 Oct 2006, Adrian Maier wrote: > > 2. Where is the TProcess documented on the freepascal website? I had > found a FCL.pdf some time ago , but I am unable to find that doc on the > freepascal website. It is not documented currently. It's scheduled as the next unit to be documented.

It is documented using fpdoc:
http://lazarus-ccr.sourceforge.net/docs/fcl/process/index.html

I guess there will a similar page on www.freepascal.org too.

Vincent

Reply by email

Michael Van Canneyt
to Michael Van Canneyt: You can't. The following lines (line 107 of unix/process.inc)…
Michael Van Canneyt wrote 6 lines
> 2. Where is the TProcess documented on the freepascal website? I had > found a FCL.pdf some time ago , but I am unable to find that doc on the > freepascal website. It is not documented currently. It's scheduled as the next unit to be documented.

Eeh, forget this. it's documented (must be getting old, memory starts failing) you can find it at:

ftp://ftp.freepascal.org/pub/fpc/docs-pdf/fcl.pdf

Michael.

Reply by email

Adrian Maier
to Michael Van Canneyt: You can't. The following lines (line 107 of unix/process.inc)…
Michael Van Canneyt wrote 9 lines
> Any idea how should i quote the arguments so that they would be properly > treated by TProcess? You can't. The following lines (line 107 of unix/process.inc) Result:=StringReplace(Result,'"','',[rfReplaceAll]); Result:=StringReplace(Result,'''','',[rfReplaceAll]); Will strip all quotes inside a quoted string. Obviously, this is a bug.

It's a painful one. I was hoping to switch to TProcess instead of shell ( which isn't cross-platform ) ...

> 2. Where is the TProcess documented on the freepascal website?

Michael, Vincent ,
Thanks for the links for TProcess docs . :-)

Show quoted text 6 lines
> 3. The code returned by the called program can be got with > TProcess.ExitCode , right ? I have a situation in which a program 1 > , but TProcess.ExitCode is 0. Therefore it's impossible to detect > the failure. That can be if the program exited because of a signal.

I'm not sure if this was the case - I'll have to investigate. Anyway, is it possible to detect this situation ?

Cheers,
Adrian Maier

Reply by email

Michael Van Canneyt
to Adrian Maier
Adrian Maier wrote 13 lines
On 10/3/06, Michael Van Canneyt wrote: > > Any idea how should i quote the arguments so that they would be properly > > treated by TProcess? > > You can't. The following lines (line 107 of unix/process.inc) > Result:=StringReplace(Result,'"','',[rfReplaceAll]); > Result:=StringReplace(Result,'''','',[rfReplaceAll]); > Will strip all quotes inside a quoted string. > > Obviously, this is a bug. It's a painful one. I was hoping to switch to TProcess instead of shell ( which isn't cross-platform ) ...

The bug won't occur on windows :)

I will see about fixing it. Could you please post a bug report so it won't be forgotten.

Show quoted text 16 lines
> > 2. Where is the TProcess documented on the freepascal website? Michael, Vincent , Thanks for the links for TProcess docs . :-) > > 3. The code returned by the called program can be got with > > TProcess.ExitCode , right ? I have a situation in which a program 1 > > , but TProcess.ExitCode is 0. Therefore it's impossible to detect > > the failure. > > That can be if the program exited because of a signal. I'm not sure if this was the case - I'll have to investigate. Anyway, is it possible to detect this situation ?

Well, first of all you should do a 'IsRunning' (or running) before checking the exitcode. Only after that you can check the exit code. About the signalling, we'd need to extend TProcess for that.

Michael.

Reply by email

Adrian Maier
to Michael Van Canneyt
Michael Van Canneyt wrote 21 lines
On Tue, 3 Oct 2006, Adrian Maier wrote: > On 10/3/06, Michael Van Canneyt wrote: > > > Any idea how should i quote the arguments so that they would be properly > > > treated by TProcess? > > > > You can't. The following lines (line 107 of unix/process.inc) > > Result:=StringReplace(Result,'"','',[rfReplaceAll]); > > Result:=StringReplace(Result,'''','',[rfReplaceAll]); > > Will strip all quotes inside a quoted string. > > > > Obviously, this is a bug. > > It's a painful one. I was hoping to switch to TProcess instead of shell ( > which isn't cross-platform ) ... The bug won't occur on windows :) I will see about fixing it. Could you please post a bug report so it won't be forgotten.

Ok.

Show quoted text 12 lines
> > > 3. The code returned by the called program can be got with > > > TProcess.ExitCode , right ? I have a situation in which a program 1 > > > , but TProcess.ExitCode is 0. Therefore it's impossible to detect > > > the failure. > > > > That can be if the program exited because of a signal. > > I'm not sure if this was the case - I'll have to investigate. > Anyway, is it possible to detect this situation ? Well, first of all you should do a 'IsRunning' (or running) before checking the exitcode.

I'm using the poWaitOnExit option, so my program doesn't waits until the external process ends. All I need is to know if the external process ended successfully or not .

Only after that you can check the exit code. About the signalling, we'd need to extend TProcess for that.

I understand.

Cheers,
Adrian Maier

Reply by email

Alexander Todorov

Can you add the following to TProcess instead of using the CommandLine property: example:
property ProcessName: String - the process to be executed property Params : TStringList - list of command line params to be passed to the process

Why should quote characters be stripped as it is in the current implementation?

Reply by email

Michael Van Canneyt
to Alexander Todorov
Alexander Todorov wrote 6 lines
Can you add the following to TProcess instead of using the CommandLine property: example: property ProcessName: String - the process to be executed property Params : TStringList - list of command line params to be passed to the process

Executable and Params seems like a better choice ?

Why should quote characters be stripped as it is in the current implementation?

Some should be stripped, others not.

Michael.

Reply by email

Adrian Maier
to Adrian Maier: Ok. I'm using the poWaitOnExit option, so my program doesn't waits until the external…
Adrian Maier wrote 7 lines
> > Well, first of all you should do a 'IsRunning' (or running) before checking > the exitcode. I'm using the poWaitOnExit option, so my program doesn't waits until the external process ends. All I need is to know if the external process ended successfully or not .

Sorry for the spelling mistakes. I meant:
I'm using the poWaitOnExit option, so my program waits for the external process to end. In this case the process is surely not running anymore when I get the exitcode. All I need is to know if the external process ended successfully
or not .

Show quoted text 9 lines
> Only after that you can check the exit code. About the signalling, > we'd need to extend TProcess for that. I understand. Cheers, Adrian Maier
Adrian Maier

Reply by email

Marco van de Voort
to Michael Van Canneyt: The bug won't occur on windows :) I will see about fixing it. Could you please post a bug…
Show quoted text 10 lines
On Tue, 3 Oct 2006, Adrian Maier wrote: > > It's a painful one. I was hoping to switch to TProcess instead of shell ( > which isn't cross-platform ) ... The bug won't occur on windows :) I will see about fixing it. Could you please post a bug report so it won't be forgotten.

Wouldn't it be better to also have a way to set the parameters using an indexed property one by one instead of a cmdline?

Because this kind of interpretation issues will continue forever, since shell handling is not portable. This was
pretty much the reason for the change to array of string in ExecuteProcess and friends.

In such case, there is always a "safe" fall back.

Reply by email

Marco van de Voort
to Alexander Todorov: Can you add the following to TProcess instead of using the CommandLine property: example:…
Show quoted text 8 lines
Can you add the following to TProcess instead of using the CommandLine property: example: property ProcessName: String - the process to be executed property Params : TStringList - list of command line params to be passed to the process Why should quote characters be stripped as it is in the current implementation?

When executing, there is a difference between shell notation and the programming interface.

e.g.

program name parammeter 1 parameter 2 parameter 3

should be written on the cmdline as

"program name" "parameter 1" "parameter 2" "parameter 3"

But should be passed to a kernel function as:
filename:='/full/path/to/program name';  // no quotes;
param[0]:='parameter 1';		 // no quotes;
param[1]:='parameter 2';		 // no quotes;
param[2]:='parameter 3';		 // no quotes;

This is the difference between shell api and deeper api. E.g

shell deeper
Unix: (fp)system() (fp)exec*
winxx: shellexecute createprocess

Another usual difference between these two is that the shell versions search for the binary, while you need to pass full path to the "deeper" category of functions.

Reply by email

Alexander Todorov
Marco van de Voort wrote 35 lines
> Can you add the following to TProcess instead of using the CommandLine property: > example: > property ProcessName: String - the process to be executed > property Params : TStringList - list of command line params to be > passed to the process > > Why should quote characters be stripped as it is in the current > implementation? When executing, there is a difference between shell notation and the programming interface. e.g. program name parammeter 1 parameter 2 parameter 3 should be written on the cmdline as "program name" "parameter 1" "parameter 2" "parameter 3" But should be passed to a kernel function as: filename:='/full/path/to/program name'; // no quotes; param[0]:='parameter 1'; // no quotes; param[1]:='parameter 2'; // no quotes; param[2]:='parameter 3'; // no quotes; This is the difference between shell api and deeper api. E.g shell deeper Unix: (fp)system() (fp)exec* winxx: shellexecute createprocess Another usual difference between these two is that the shell versions search for the binary, while you need to pass full path to the "deeper" category of functions.

Thanks for the explanation.

Reply by email

Adrian Maier
to Marco van de Voort: Wouldn't it be better to also have a way to set the parameters using an indexed property…
Marco van de Voort wrote 20 lines
> On Tue, 3 Oct 2006, Adrian Maier wrote: > > > > It's a painful one. I was hoping to switch to TProcess instead of shell ( > > which isn't cross-platform ) ... > > The bug won't occur on windows :) > > I will see about fixing it. Could you please post a bug report so it won't > be forgotten. Wouldn't it be better to also have a way to set the parameters using an indexed property one by one instead of a cmdline? Because this kind of interpretation issues will continue forever, since shell handling is not portable. This was pretty much the reason for the change to array of string in ExecuteProcess and friends. In such case, there is always a "safe" fall back.

It seems nice to have a way of specifying parameters like that (in which case I assume that strings given will be passed as-they-are).

There is one more thing about TProcess that i've been surprised to see that after:

   proc.Environment.Append('PGDATABASE=db1');

all the variables inherited from the parent process are no longer passed to the external program by TProcess.

The behaviour is documented :
" Environment contains the environment for the new process; it's a list of Name=Value pairs, one per line. If it is empty, the environment of the current process is passed on to the new process. "

So, initially the Environment is empty and the program inherits the variables. When I append the first variable, it will no longer inherit the variables.

I find the behaviour counterintuitive: the first "append" causes the Environment to
be initialised.

I haven't discovered yet how could the programmer preserve the inherited environment
and only "add" some variables ?

Don't you think that by default the Environment list should be filled with the current
environment? This way "append" would mean indeed "append". It would also be easy to clear the Environment if needed.

Adrian Maier

Reply by email

Andrew Haines
to Adrian Maier
Adrian Maier wrote 11 lines
So, initially the Environment is empty and the program inherits the variables. When I append the first variable, it will no longer inherit the variables. I find the behaviour counterintuitive: the first "append" causes the Environment to be initialised. I haven't discovered yet how could the programmer preserve the inherited environment and only "add" some variables ?

This copies all the envvars to a stringlist. You can add your own of course too.

function GetEnvironmentVars: TStringList;
var
  I: Integer;
  fName: String;
begin
  Result := TStringList.Create;
  for I := 0 to GetEnvironmentVariableCount-1 do begin
    fName := GetEnvironmentString(I);
    Result.Add(fName);
  end;
end;

HTH

Andrew Haines

Reply by email

Alexander Todorov
Adrian Maier wrote
It seems nice to have a way of specifying parameters like that (in which case I assume that strings given will be passed as-they-are).

Another option is to use escaping for quote characters (and maybe some others) when specifying the TProcess.CommandLine property.

Reply by email

Adrian Maier
to Adrian Maier: Ok. I'm using the poWaitOnExit option, so my program doesn't waits until the external…
Adrian Maier wrote 22 lines
On 10/3/06, Michael Van Canneyt wrote: > > On Tue, 3 Oct 2006, Adrian Maier wrote: > > > On 10/3/06, Michael Van Canneyt wrote: > > > > Any idea how should i quote the arguments so that they would be properly > > > > treated by TProcess? > > > > > > You can't. The following lines (line 107 of unix/process.inc) > > > Result:=StringReplace(Result,'"','',[rfReplaceAll]); > > > Result:=StringReplace(Result,'''','',[rfReplaceAll]); > > > Will strip all quotes inside a quoted string. > > > > > > Obviously, this is a bug. > > > > It's a painful one. I was hoping to switch to TProcess instead of shell ( > > which isn't cross-platform ) ... > > The bug won't occur on windows :) > I will see about fixing it. Could you please post a bug report so it won't > be forgotten.

Hello guys,

Luckily I have discovered a workaround . It is possible to add the simple quotes
later, inside the sql script. So, it is ok to run something like : psql -f abc.sql -v DATE1=1-jan-2006

if I add at the beginning of the script:
\set DATE1 '\'':DATE1'\''

Chers !
Adrian Maier

Reply by email