📄 ch16_03.htm
字号:
<HTML><HEAD><TITLE>Recipe 16.2. Running Another Program (Perl Cookbook)</TITLE><METANAME="DC.title"CONTENT="Perl Cookbook"><METANAME="DC.creator"CONTENT="Tom Christiansen & Nathan Torkington"><METANAME="DC.publisher"CONTENT="O'Reilly & Associates, Inc."><METANAME="DC.date"CONTENT="1999-07-02T01:43:39Z"><METANAME="DC.type"CONTENT="Text.Monograph"><METANAME="DC.format"CONTENT="text/html"SCHEME="MIME"><METANAME="DC.source"CONTENT="1-56592-243-3"SCHEME="ISBN"><METANAME="DC.language"CONTENT="en-US"><METANAME="generator"CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"><LINKREV="made"HREF="mailto:online-books@oreilly.com"TITLE="Online Books Comments"><LINKREL="up"HREF="ch16_01.htm"TITLE="16. Process Management and Communication"><LINKREL="prev"HREF="ch16_02.htm"TITLE="16.1. Gathering Output from a Program"><LINKREL="next"HREF="ch16_04.htm"TITLE="16.3. Replacing the Current Program with a Different One"></HEAD><BODYBGCOLOR="#FFFFFF"><img alt="Book Home" border="0" src="gifs/smbanner.gif" usemap="#banner-map" /><map name="banner-map"><area shape="rect" coords="1,-2,616,66" href="index.htm" alt="Perl Cookbook"><area shape="rect" coords="629,-11,726,25" href="jobjects/fsearch.htm" alt="Search this book" /></map><div class="navbar"><p><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch16_02.htm"TITLE="16.1. Gathering Output from a Program"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 16.1. Gathering Output from a Program"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><B><FONTFACE="ARIEL,HELVETICA,HELV,SANSERIF"SIZE="-1"><ACLASS="chapter"REL="up"HREF="ch16_01.htm"TITLE="16. Process Management and Communication"></A></FONT></B></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch16_04.htm"TITLE="16.3. Replacing the Current Program with a Different One"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 16.3. Replacing the Current Program with a Different One"BORDER="0"></A></TD></TR></TABLE></DIV><DIVCLASS="sect1"><H2CLASS="sect1"><ACLASS="title"NAME="ch16-29784">16.2. Running Another Program</A></H2><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch16-pgfId-860">Problem<ACLASS="indexterm"NAME="ch16-idx-1000006245-0"></A><ACLASS="indexterm"NAME="ch16-idx-1000006245-1"></A></A></H3><PCLASS="para">You want to run another program from your own, pause until the other program is done, and then continue. The other program should have same STDIN and STDOUT as you have.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch16-pgfId-866">Solution</A></H3><PCLASS="para">Call <CODECLASS="literal">system</CODE><ACLASS="indexterm"NAME="ch16-idx-1000006251-0"></A> with a string to have the shell interpret the string as a command line:</P><PRECLASS="programlisting">$status = system("vi $myfile");</PRE><PCLASS="para">If you don't want the shell involved, pass <CODECLASS="literal">system</CODE> a list:</P><PRECLASS="programlisting">$status = system("vi", $myfile);</PRE></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch16-pgfId-878">Discussion</A></H3><PCLASS="para">The <CODECLASS="literal">system</CODE> function is the simplest and most generic way to run another program in Perl. It doesn't gather the program's STDOUT like backticks or <CODECLASS="literal">open</CODE>. Instead, its return value is (essentially) that program's exit status. While the new program is running, your main program is suspended, so the new program can read from your STDIN and write to your STDOUT so users can interact with it.</P><PCLASS="para">Like <CODECLASS="literal">open</CODE>, <CODECLASS="literal">exec</CODE>, and backticks, <CODECLASS="literal">system</CODE> uses the shell to start the program whenever it's called with one argument. This is convenient when you want to do redirection or other tricks:</P><PRECLASS="programlisting">system("cmd1 args | cmd2 | cmd3 >outfile");system("cmd args <infile >outfile 2>errfile");</PRE><PCLASS="para">To avoid the shell, call <CODECLASS="literal">system</CODE> with a list of arguments:</P><PRECLASS="programlisting">$status = system($program, $arg1, $arg);die "$program exited funny: $?" unless $status == 0;</PRE><PCLASS="para">The returned status value is not just the exit value: it includes the signal number (if any) that the process died from. This is the same value that <CODECLASS="literal">wait</CODE> sets <CODECLASS="literal">$?</CODE> to. See <ACLASS="xref"HREF="ch16_20.htm"TITLE="Avoiding Zombie Processes">Recipe 16.19</A> to learn how to decode this value.</P><PCLASS="para">The <CODECLASS="literal">system</CODE> function (but not backticks) ignores SIGINT and SIGQUIT while child processes are running. That way those signals will kill only the child process. If you want your main program to die as well, check the return value of <CODECLASS="literal">system</CODE>, or the value of the <CODECLASS="literal">$?</CODE> variable.</P><PRECLASS="programlisting">if (($signo = system(@arglist)) &= 127) { die "program killed by signal $signo\n";}</PRE><PCLASS="para">To get the effect of a <CODECLASS="literal">system</CODE> that ignores SIGINT, install your own signal handler and then manually <CODECLASS="literal">fork</CODE> and <CODECLASS="literal">exec</CODE>:</P><PRECLASS="programlisting">if ($pid = fork) { # parent catches INT and berates user local $SIG{INT} = sub { print "Tsk tsk, no process interruptus\n" }; waitpid($pid, 0);} else { die "cannot fork: $!" unless defined $pid; # child ignores INT and does its thing $SIG{INT} = "IGNORE"; exec("summarize", "/etc/logfiles") or die "Can't exec: $!\n";}</PRE><PCLASS="para">A few programs examine their own program name. Shells look to see whether they were called with a leading minus to indicate interactivity. The <EMCLASS="emphasis">expn</EM> program at the end of Chapter 18 behaves differently if called as <EMCLASS="emphasis">vrfy</EM>, which can happen if you've installed the file under two different links as suggested. This is why you shouldn't trust that <CODECLASS="literal">$0</CODE> is really the pathname to the invoked program - you could have been lied to in a number of ways.</P><PCLASS="para">If you want to fib to the program you're executing about its own name, specify the real path as the "indirect object" in front of the list passed to <CODECLASS="literal">system</CODE>. (This also works with <CODECLASS="literal">exec</CODE>.) The indirect object has no comma following it, just like using <CODECLASS="literal">printf</CODE> with a filehandle or making object methods without the pointer arrow.</P><PRECLASS="programlisting">$shell = '/bin/tcsh';system $shell '-csh'; # pretend it's a login shell</PRE><PCLASS="para">Or, more directly:</P><PRECLASS="programlisting">system {'/bin/tcsh'} '-csh'; # pretend it's a login shell</PRE><PCLASS="para">In the next example, the program's real pathname is supplied in the indirect object slot as <CODECLASS="literal">{'/home/tchrist/scripts/expn'}</CODE>. The fictitious name <CODECLASS="literal">'vrfy</CODE>' is given as the first real function argument, which the program will see stored in <CODECLASS="literal">$0</CODE>.</P><PRECLASS="programlisting"># call expn as vrfysystem {'/home/tchrist/scripts/expn'} 'vrfy', @ADDRESSES;</PRE><PCLASS="para">Using an indirect object with <CODECLASS="literal">system</CODE> is also more secure. This usage forces interpretation of the arguments as a multivalued list, even if the list had just one argument. That way you're safe from the shell expanding wildcards or splitting up words with whitespace in them.</P><PRECLASS="programlisting">@args = ( "echo surprise" );system @args; # subject to shell escapes if @args == 1system { $args[0] } @args; # safe even with one-arg list</PRE><PCLASS="para">The first version, the one without the indirect object, ran the <EMCLASS="emphasis">echo</EM> program, passing it <CODECLASS="literal">"surprise"</CODE> an argument. The second version didn't - it tried to run a program literally called <CODECLASS="literal">"echo</CODE> <CODECLASS="literal">surprise"</CODE>, didn't find it, and set <CODECLASS="literal">$?</CODE> to a non-zero value indicating failure.<ACLASS="indexterm"NAME="ch16-idx-1000006253-0"></A><ACLASS="indexterm"NAME="ch16-idx-1000006253-1"></A><ACLASS="indexterm"NAME="ch16-idx-1000006253-2"></A></P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch16-pgfId-1000005848">See Also</A></H3><PCLASS="para">The section on <ACLASS="olink"HREF="../prog/ch06_03.htm">"Cooperating with Strangers"</A> in <ACLASS="olink"HREF="../prog/ch06_01.htm">Chapter 6</A> of <ACLASS="citetitle"HREF="../prog/index.htm"TITLE="Programming Perl"><CITECLASS="citetitle">Programming Perl</CITE></A>, or <ICLASS="filename">perlsec </I>(1); the <ACLASS="olink"HREF="../prog/ch03_190.htm"><CODECLASS="literal">waitpid</CODE></A>, <ACLASS="olink"HREF="../prog/ch03_040.htm"><CODECLASS="literal">fork</CODE></A>, <ACLASS="olink"HREF="../prog/ch03_033.htm"><CODECLASS="literal">exec</CODE></A>, <ACLASS="olink"HREF="../prog/ch03_167.htm"><CODECLASS="literal">system</CODE></A>, and <ACLASS="olink"HREF="../prog/ch03_102.htm"><CODECLASS="literal">open</CODE></A> functions in <ACLASS="olink"HREF="../prog/ch03_01.htm">Chapter 3</A> of <ACLASS="citetitle"HREF="../prog/index.htm"TITLE="Programming Perl"><CITECLASS="citetitle">Programming Perl</CITE></A> or <ICLASS="filename">perlfunc </I>(1); <ACLASS="xref"HREF="ch16_02.htm"TITLE="Gathering Output from a Program">Recipe 16.1</A>; <ACLASS="xref"HREF="ch16_05.htm"TITLE="Reading or Writing to Another Program">Recipe 16.4</A>; <ACLASS="xref"HREF="ch16_20.htm"TITLE="Avoiding Zombie Processes">Recipe 16.19</A>; <ACLASS="xref"HREF="ch19_07.htm"TITLE="Executing Commands Without Shell Escapes">Recipe 19.6</A>; <CITECLASS="citetitle">Advanced Programming in the UNIX Environment</CITE>, by Richard W. Stevens; Addison-Wesley (1992)</P></DIV></DIV><DIVCLASS="htmlnav"><P></P><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch16_02.htm"TITLE="16.1. Gathering Output from a Program"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 16.1. Gathering Output from a Program"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="book"HREF="index.htm"TITLE="Perl Cookbook"><IMGSRC="../gifs/txthome.gif"ALT="Perl Cookbook"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch16_04.htm"TITLE="16.3. Replacing the Current Program with a Different One"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 16.3. Replacing the Current Program with a Different One"BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228">16.1. Gathering Output from a Program</TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="index"HREF="index/index.htm"TITLE="Book Index"><IMGSRC="../gifs/index.gif"ALT="Book Index"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228">16.3. Replacing the Current Program with a Different One</TD></TR></TABLE><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><FONTSIZE="-1"></DIV<!-- LIBRARY NAV BAR --> <img src="../gifs/smnavbar.gif" usemap="#library-map" border="0" alt="Library Navigation Links"><p> <a href="copyrght.htm">Copyright © 2002</a> O'Reilly & Associates. All rights reserved.</font> </p> <map name="library-map"> <area shape="rect" coords="1,0,85,94" href="../index.htm"><area shape="rect" coords="86,1,178,103" href="../lwp/index.htm"><area shape="rect" coords="180,0,265,103" href="../lperl/index.htm"><area shape="rect" coords="267,0,353,105" href="../perlnut/index.htm"><area shape="rect" coords="354,1,446,115" href="../prog/index.htm"><area shape="rect" coords="448,0,526,132" href="../tk/index.htm"><area shape="rect" coords="528,1,615,119" href="../cookbook/index.htm"><area shape="rect" coords="617,0,690,135" href="../pxml/index.htm"></map> </BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -