Shell Commands (Getting PID and Timing Them)

H

Hal Vaughan

There may be a better way to do what I want to do, so I'm open to
suggestions.

I want to run a shell command to record sound, and kill it after x seconds.
If I were writing a Bash script, I'd run the command in the background, get
the PID, use a sleep statement, then kill the first command after the sleep
statement. In Perl I know how to fork and get a PID, and I know how to use
`command` to get a commands output, but I can't find a way to run a command
from Perl and get the PID so I can kill it when I want.

Is there a way to get the PID? (I'd rather not use a 2nd script in bash to
do it.)

If there's another way to execute a shell command from Perl, then after x
seconds kill it, I'm open to it.

Thanks!

Hal
 
A

axel

Hal Vaughan said:
I want to run a shell command to record sound, and kill it after x seconds.
If I were writing a Bash script, I'd run the command in the background, get
the PID, use a sleep statement, then kill the first command after the sleep
statement. In Perl I know how to fork and get a PID, and I know how to use
`command` to get a commands output, but I can't find a way to run a command
from Perl and get the PID so I can kill it when I want.
Is there a way to get the PID? (I'd rather not use a 2nd script in bash to
do it.)
If there's another way to execute a shell command from Perl, then after x
seconds kill it, I'm open to it.

Something like...

my $pid = open (PIPE, "-|") || exec("/what/ever");

# Read from PIPE, have a cup of coffee, sleep

my $kesult = kill 9, $pid;

Axel
 
J

Joe Smith

Hal said:
In Perl I know how to fork and get a PID, and I know how to use
`command` to get a commands output, but I can't find a way to run a command
from Perl and get the PID so I can kill it when I want.

my $child_pid = fork();
die unless defined $child_pid;
if ($child_pid) { # Parent
sleep $sleep_time;
kill 2,$child_pid;
} else { # Child
exec "command </dev/null >/dev/null 2>&1";
die "Could not run 'command'";
}
-Joe
 
H

Hal Vaughan

Joe said:
my $child_pid = fork();
die unless defined $child_pid;
if ($child_pid) { # Parent
sleep $sleep_time;
kill 2,$child_pid;
} else { # Child
exec "command </dev/null >/dev/null 2>&1";
die "Could not run 'command'";
}
-Joe

Thanks, but that gives me the PID of the forked process. I want to run a
BASH command from Perl, and get the PID of the BASH command. The child_pid
is not the same as the bash command.

Hal
 
H

Hal Vaughan

Something like...

my $pid = open (PIPE, "-|") || exec("/what/ever");

# Read from PIPE, have a cup of coffee, sleep

my $kesult = kill 9, $pid;

Axel

I could use a bit of help understanding this. When the pipe is opened, and
with the "||", it will exec the program, but still continue with the rest
of the Perl program, with the pipe still open? (I'm just trying to make
sure I see what's going on here.)

Hal
 
A

axel

Hal Vaughan said:
(e-mail address removed) wrote:
I could use a bit of help understanding this. When the pipe is opened, and
with the "||", it will exec the program, but still continue with the rest
of the Perl program, with the pipe still open? (I'm just trying to make
sure I see what's going on here.)

Yes. The pipe would be open for reading in this case. A simple
example... assuming we have the shell script hello.sh:

#!/bin/sh
echo Hello from a shell script

and the Perl script:

#!/usr/bin/perl

use warnings;
use strict;

my $pid = open (PIPE, "-|") || exec("./hello.sh");
while (<PIPE>) {
print "Received: ", $_;
}
close (PIPE);
__END__

The Perl script will fork a child which exec's hello.sh and then reads
the output from the childs which will be:

Received: Hello from a shell script

and the closes the PIPE and kills the child (although the child should
be dead by this time). Of course you may well want to do checks on the
status returned by the close statement to see if there was an abnormal
termination.

Axel
 
A

Anno Siegel

Hal Vaughan said:
Thanks, but that gives me the PID of the forked process. I want to run a
BASH command from Perl, and get the PID of the BASH command. The child_pid
is not the same as the bash command.

Have you tried the code? Have you read "perldoc -f exec"? What is a
BASH-command?

Anno
 
T

Tad McClellan

Hal Vaughan said:
Thanks, but that gives me the PID of the forked process.


Which is the process that you want to time-out.

I want to run a
BASH command from Perl, and get the PID of the BASH command.


You got it (if /bin/sh is bash on your system. If not then
replace "command" above with "/bin/bash").

The child_pid
is not the same as the bash command.


Yes it is.

Why do you think they are different?
 
H

Hal Vaughan

Anno said:
Have you tried the code? Have you read "perldoc -f exec"? What is a
BASH-command?

Anno

Tried it with typos. It works now. I saw the other suggested solution and
tried it first. Unfortunately, at later than 3 am, I didn't follow this
example (with the forking) as well as I should have, and misunderstood what
it was doing and what I was looking at.

Funny how things make better sense after a few hours of sleep...

Hal
 
J

Joe Smith

Hal said:
I could use a bit of help understanding this. When the pipe is opened, and
with the "||", it will exec the program, but still continue with the rest
of the Perl program, with the pipe still open?

No, exec() and "continue with the rest of the program" are mutually
exclusive. The exec() function causes your computer to stop
executing the perl program and execute the other program instead.
A single process won't do both, but a parent process and a child
process can.

*) open(PIPE,"-|") does an implicit fork() to create a child process
and creates a pipe.

*) In the parent process: Set file handle PIPE to read from the
child process. Return the pid of the child (which is nonzero).

*) In the parent process: The statement evaluates to
(a value which is true) || exec();
which means that the exec() part is not executed. Perl continues
with the next statement.

*) In the child process: TConnect the pipe to STDOUT.
The open() function returns false in the child.

*) In the child process: The statement evaluates to
(a value which is false) || exec();
which means the exec() function will be invoked. If the
exec() is successful, the rest of the perl program will not
be executed.

The key to understanding how open(FH,'-|') works is to first
understand how fork() returns two different values.

-Joe
 
B

Brian McCauley

my $pid = open (PIPE, "-|") || exec("/what/ever");

Why not just do it in one step?

my $pid = open (PIPE, '-|', '/what/ever')
or die "Whatever failed: $!";
 
B

Brian McCauley

Tad said:
Which is the process that you want to time-out.
You got it (if /bin/sh is bash on your system. If not then
replace "command" above with "/bin/bash").

That would be:

exec "/bin/bash </dev/null >/dev/null 2>&1";

Er no, that would run bash instead of command, not run command under bash.

To force the command line to be processed by /bin/bash rather than /bin/sh:

exec '/bin/bash', '-c', 'command </dev/null >/dev/null 2>&1';
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top