=head1 NAME
-perlfaq8 - System Interaction ($Revision: 1.39 $, $Date: 1999/05/23 18:37:57 $)
+perlfaq8 - System Interaction ($Revision: 1.14 $, $Date: 2002/11/10 17:35:47 $)
=head1 DESCRIPTION
There's an example of this in L<perlfunc/crypt>). First, you put the
terminal into "no echo" mode, then just read the password normally.
You may do this with an old-style ioctl() function, POSIX terminal
-control (see L<POSIX> and Chapter 7 of the Camel, 2nd ed.), or a call
+control (see L<POSIX> or its documentation the Camel Book), or a call
to the B<stty> program, with varying degrees of portability.
You can also do this for most systems using the Term::ReadKey module
DEV->autoflush(1);
As mentioned in the previous item, this still doesn't work when using
-socket I/O between Unix and Macintosh. You'll need to hardcode your
+socket I/O between Unix and Macintosh. You'll need to hard code your
line terminators, in that case.
=item non-blocking input
# been opened on a pipe...
system("/bin/stty $stty");
$_ = <MODEM_IN>;
- chop;
+ chomp;
if ( !m/^Connected/ ) {
print STDERR "$0: cu printed `$_' instead of `Connected'\n";
}
=head2 How do I start a process in the background?
-You could use
+Several modules can start other processes that do not block
+your Perl program. You can use IPC::Open3, Parallel::Jobs,
+IPC::Run, and some of the POE modules. See CPAN for more
+details.
+
+You could also use
system("cmd &")
=item Zombies
-You have to be prepared to "reap" the child process when it finishes
+You have to be prepared to "reap" the child process when it finishes.
$SIG{CHLD} = sub { wait };
+
+ $SIG{CHLD} = 'IGNORE';
+
+You can also use a double fork. You immediately wait() for your
+first child, and the init daemon will wait() for your grandchild once
+it exits.
+
+ unless ($pid = fork) {
+ unless (fork) {
+ exec "what you really wanna do";
+ die "exec failed!";
+ }
+ exit 0;
+ }
+ waitpid($pid,0);
+
See L<perlipc/"Signals"> for other examples of code to do this.
Zombies are not an issue with C<system("prog &")>.
You don't actually "trap" a control character. Instead, that character
generates a signal which is sent to your terminal's currently
foregrounded process group, which you then trap in your process.
-Signals are documented in L<perlipc/"Signals"> and chapter 6 of the Camel.
+Signals are documented in L<perlipc/"Signals"> and the
+section on ``Signals'' in the Camel.
Be warned that very few C libraries are re-entrant. Therefore, if you
attempt to print() in a handler that got invoked during another stdio
you're in a "slow" call, such as <FH>, read(), connect(), or
wait(), that the only way to terminate them is by "longjumping" out;
that is, by raising an exception. See the time-out handler for a
-blocking flock() in L<perlipc/"Signals"> or chapter 6 of the Camel, 2nd ed.
+blocking flock() in L<perlipc/"Signals"> or the section on ``Signals''
+in the Camel book.
=head2 How do I modify the shadow password file on a Unix system?
basis.) This mechanism will work for Unix, MS-DOS, Windows, and NT;
the VMS equivalent is C<set time>.
-However, if all you want to do is change your timezone, you can
+However, if all you want to do is change your time zone, you can
probably get away with setting an environment variable:
$ENV{TZ} = "MST7MDT"; # unixish
If you want finer granularity than the 1 second that the sleep()
function provides, the easiest way is to use the select() function as
documented in L<perlfunc/"select">. Try the Time::HiRes and
-the BSD::Itimer modules (available from CPAN).
+the BSD::Itimer modules (available from CPAN, and starting from
+Perl 5.8 Time::HiRes is part of the standard distribution).
=head2 How can I measure time under a second?
In general, you may not be able to. The Time::HiRes module (available
-from CPAN) provides this functionality for some systems.
+from CPAN, and starting from Perl 5.8 part of the standard distribution)
+provides this functionality for some systems.
If your system supports both the syscall() function in Perl as well as
a system call like gettimeofday(2), then you may be able to do
Perl's exception-handling mechanism is its eval() operator. You can
use eval() as setjmp and die() as longjmp. For details of this, see
the section on signals, especially the time-out handler for a blocking
-flock() in L<perlipc/"Signals"> and chapter 6 of the Camel 2nd ed.
+flock() in L<perlipc/"Signals"> or the section on ``Signals'' in
+the Camel Book.
If exception handling is all you're interested in, try the
exceptions.pl library (part of the standard perl distribution).
The IPC::Open2 module (part of the standard perl distribution) is an
easy-to-use approach that internally uses pipe(), fork(), and exec() to do
the job. Make sure you read the deadlock warnings in its documentation,
-though (see L<IPC::Open2>). See L<perlipc/"Bidirectional Communication
-with Another Process"> and L<perlipc/"Bidirectional Communication with
-Yourself">
+though (see L<IPC::Open2>). See
+L<perlipc/"Bidirectional Communication with Another Process"> and
+L<perlipc/"Bidirectional Communication with Yourself">
You may also use the IPC::Open3 module (part of the standard perl
distribution), but be warned that it has a different order of
script's STDOUT and STDERR, unless the system() command redirects them.
Backticks and open() read B<only> the STDOUT of your command.
+You can also use the open3() function from IPC::Open3. Benjamin
+Goldberg provides some sample code:
+
+To capture a program's STDOUT, but discard its STDERR:
+
+ use IPC::Open3;
+ use File::Spec;
+ use Symbol qw(gensym);
+ open(NULL, ">", File::Spec->devnull);
+ my $pid = open3(gensym, \*PH, ">&NULL", "cmd");
+ while( <PH> ) { }
+ waitpid($pid, 0);
+
+To capture a program's STDERR, but discard its STDOUT:
+
+ use IPC::Open3;
+ use File::Spec;
+ use Symbol qw(gensym);
+ open(NULL, ">", File::Spec->devnull);
+ my $pid = open3(gensym, ">&NULL", \*PH, "cmd");
+ while( <PH> ) { }
+ waitpid($pid, 0);
+
+To capture a program's STDERR, and let its STDOUT go to our own STDERR:
+
+ use IPC::Open3;
+ use Symbol qw(gensym);
+ my $pid = open3(gensym, ">&STDERR", \*PH, "cmd");
+ while( <PH> ) { }
+ waitpid($pid, 0);
+
+To read both a command's STDOUT and its STDERR separately, you can
+redirect them to temp files, let the command run, then read the temp
+files:
+
+ use IPC::Open3;
+ use Symbol qw(gensym);
+ use IO::File;
+ local *CATCHOUT = IO::File->new_tempfile;
+ local *CATCHERR = IO::File->new_tempfile;
+ my $pid = open3(gensym, ">&CATCHOUT", ">&CATCHERR", "cmd");
+ waitpid($pid, 0);
+ seek $_, 0, 0 for \*CATCHOUT, \*CATCHERR;
+ while( <CATCHOUT> ) {}
+ while( <CATCHERR> ) {}
+
+But there's no real need for *both* to be tempfiles... the following
+should work just as well, without deadlocking:
+
+ use IPC::Open3;
+ use Symbol qw(gensym);
+ use IO::File;
+ local *CATCHERR = IO::File->new_tempfile;
+ my $pid = open3(gensym, \*CATCHOUT, ">&CATCHERR", "cmd");
+ while( <CATCHOUT> ) {}
+ waitpid($pid, 0);
+ seek CATCHERR, 0, 0;
+ while( <CATCHERR> ) {}
+
+And it'll be faster, too, since we can begin processing the program's
+stdout immediately, rather than waiting for the program to finish.
+
With any of these, you can change file descriptors before the call:
open(STDOUT, ">logfile");
Note that you I<must> use Bourne shell (sh(1)) redirection syntax in
backticks, not csh(1)! Details on why Perl's system() and backtick
-and pipe opens all use the Bourne shell are in
-http://www.perl.com/CPAN/doc/FMTEYEWTK/versus/csh.whynot .
-To capture a command's STDERR and STDOUT together:
+and pipe opens all use the Bourne shell are in the
+F<versus/csh.whynot> article in the "Far More Than You Ever Wanted To
+Know" collection in http://www.cpan.org/misc/olddoc/FMTEYEWTK.tgz . To
+capture a command's STDERR and STDOUT together:
$output = `cmd 2>&1`; # either with backticks
$pid = open(PH, "cmd 2>&1 |"); # or with an open pipe
=head2 Why doesn't open() return an error when a pipe open fails?
-Because the pipe open takes place in two steps: first Perl calls
-fork() to start a new process, then this new process calls exec() to
-run the program you really wanted to open. The first step reports
-success or failure to your process, so open() can only tell you
-whether the fork() succeeded or not.
-
-To find out if the exec() step succeeded, you have to catch SIGCHLD
-and wait() to get the exit status. You should also catch SIGPIPE if
-you're writing to the child--you may not have found out the exec()
-failed by the time you write. This is documented in L<perlipc>.
+If the second argument to a piped open() contains shell
+metacharacters, perl fork()s, then exec()s a shell to decode the
+metacharacters and eventually run the desired program. If the program
+couldn't be run, it's the shell that gets the message, not Perl. All
+your Perl program can find out is whether the shell itself could be
+successfully started. You can still capture the shell's STDERR and
+check it for error messages. See L<"How can I capture STDERR from an
+external command?"> elsewhere in this document, or use the
+IPC::Open3 module.
-In some cases, even this won't work. If the second argument to a
-piped open() contains shell metacharacters, perl fork()s, then exec()s
-a shell to decode the metacharacters and eventually run the desired
-program. Now when you call wait(), you only learn whether or not the
-I<shell> could be successfully started...it's best to avoid shell
-metacharacters.
-
-On systems that follow the spawn() paradigm, open() I<might> do what
-you expect--unless perl uses a shell to start your command. In this
-case the fork()/exec() description still applies.
+If there are no shell metacharacters in the argument of open(), Perl
+runs the command directly, without using the shell, and can correctly
+report whether the command started.
=head2 What's wrong with using backticks in a void context?
Strictly speaking, nothing. Stylistically speaking, it's not a good
-way to write maintainable code because backticks have a (potentially
-humongous) return value, and you're ignoring it. It's may also not be very
-efficient, because you have to read in all the lines of output, allocate
-memory for them, and then throw it away. Too often people are lulled
-to writing:
-
- `cp file file.bak`;
+way to write maintainable code. Perl has several operators for
+running external commands. Backticks are one; they collect the output
+from the command for use in your program. The C<system> function is
+another; it doesn't do this.
-And now they think "Hey, I'll just always use backticks to run programs."
-Bad idea: backticks are for capturing a program's output; the system()
-function is for running programs.
+Writing backticks in your program sends a clear message to the readers
+of your code that you wanted to collect the output of the command.
+Why send a clear message that isn't true?
Consider this line:
`cat /etc/termcap`;
-You haven't assigned the output anywhere, so it just wastes memory
-(for a little while). You forgot to check C<$?> to see whether
-the program even ran correctly, too. Even if you wrote
+You forgot to check C<$?> to see whether the program even ran
+correctly. Even if you wrote
print `cat /etc/termcap`;
=head2 How can I call backticks without shell processing?
-This is a bit tricky. Instead of writing
+This is a bit tricky. You can't simply write the command
+like this:
@ok = `grep @opts '$search_string' @filenames`;
-You have to do this:
+As of Perl 5.8.0, you can use open() with multiple arguments.
+Just like the list forms of system() and exec(), no shell
+escapes happen.
+
+ open( GREP, "-|", 'grep', @opts, $search_string, @filenames );
+ chomp(@ok = <GREP>);
+ close GREP;
+
+You can also:
my @ok = ();
if (open(GREP, "-|")) {
Just as with system(), no shell escapes happen when you exec() a list.
Further examples of this can be found in L<perlipc/"Safe Pipe Opens">.
-Note that if you're stuck on Microsoft, no solution to this vexing issue
+Note that if you're use Microsoft, no solution to this vexing issue
is even possible. Even if Perl were to emulate fork(), you'd still
-be hosed, because Microsoft gives no argc/argv-style API. Their API
-always reparses from a single string, which is fundamentally wrong,
-but you're not likely to get the Gods of Redmond to acknowledge this
-and fix it for you.
+be stuck, because Microsoft does not have a argc/argv-style API.
=head2 Why can't my script read from STDIN after I gave it EOF (^D on Unix, ^Z on MS-DOS)?
=head2 Can I use perl to run a telnet or ftp session?
Try the Net::FTP, TCP::Client, and Net::Telnet modules (available from
-CPAN). http://www.perl.com/CPAN/scripts/netstuff/telnet.emul.shar
+CPAN). http://www.cpan.org/scripts/netstuff/telnet.emul.shar
will also help for emulating the telnet protocol, but Net::Telnet is
quite probably easier to use..
=head2 How do I timeout a slow event?
Use the alarm() function, probably in conjunction with a signal
-handler, as documented in L<perlipc/"Signals"> and chapter 6 of the
-Camel. You may instead use the more flexible Sys::AlarmCall module
-available from CPAN.
+handler, as documented in L<perlipc/"Signals"> and the section on
+``Signals'' in the Camel. You may instead use the more flexible
+Sys::AlarmCall module available from CPAN.
+
+The alarm() function is not implemented on all versions of Windows.
+Check the documentation for your specific version of Perl.
=head2 How do I set CPU limits?
Use the reaper code from L<perlipc/"Signals"> to call wait() when a
SIGCHLD is received, or else use the double-fork technique described
-in L<perlfunc/fork>.
+in L<perlfaq8/"How do I start a process in the background?">.
=head2 How do I use an SQL database?
There are a number of excellent interfaces to SQL databases. See the
-DBD::* modules available from http://www.perl.com/CPAN/modules/DBD .
-A lot of information on this can be found at
-http://www.symbolstone.org/technology/perl/DBI/
+DBD::* modules available from http://www.cpan.org/modules/by-module/DBD/ .
+A lot of information on this can be found at http://dbi.perl.org/
=head2 How do I make a system() exit on control-C?
=head2 How do I install a module from CPAN?
The easiest way is to have a module also named CPAN do it for you.
-This module comes with perl version 5.004 and later. To manually install
-the CPAN module, or any well-behaved CPAN module for that matter, follow
-these steps:
+This module comes with perl version 5.004 and later.
+
+ $ perl -MCPAN -e shell
+
+ cpan shell -- CPAN exploration and modules installation (v1.59_54)
+ ReadLine support enabled
+
+ cpan> install Some::Module
+
+To manually install the CPAN module, or any well-behaved CPAN module
+for that matter, follow these steps:
=over 4
=head1 AUTHOR AND COPYRIGHT
-Copyright (c) 1997-1999 Tom Christiansen and Nathan Torkington.
+Copyright (c) 1997-2002 Tom Christiansen and Nathan Torkington.
All rights reserved.
-When included as part of the Standard Version of Perl, or as part of
-its complete documentation whether printed or otherwise, this work
-may be distributed only under the terms of Perl's Artistic License.
-Any distribution of this file or derivatives thereof I<outside>
-of that package require that special arrangements be made with
-copyright holder.
+This documentation is free; you can redistribute it and/or modify it
+under the same terms as Perl itself.
Irrespective of its distribution, all code examples in this file
are hereby placed into the public domain. You are permitted and