Perl笔记14、进程管理
system 函数system函数是Perl中启动子进程最简单的方法。如下调用linux的date命令:
system函数可以使用单个,或多个参数的形式,其中单个函数的形式很简单,经需要运行的命令直接写在双引号即可,但如果要用到shell下的变量就不能用双引号了,这时需要用单引号代替如下: 多个参数的形式就更好理解了,将各个参数和变量用逗号隔开即可,如下:
my
$tarfile
=
"something*wicked.tar"
;
my @dirs = qw (fred |flintstone betty ) ; system "tar" , "cvf" , $tarfile , @dirs ; 说明: exec函数exec函数与上面讲的system函数的使用语法一致,只不过perl在使用exec函数调用外部程序时不会等待程序完成,而是调用起来就OK,至于这个程序是否正常执行,是否有错则不会理睬了。很多时候Perl这样做主要功能是为另一个程序执行设定运行的环境而已。一般情况下我们都是配合fork一起使用,这稍后会介绍。 环境变量Perl中的%ENV哈希存放了父进程,也就是shell中的环境变量,在Perl中可以修改这些变量,然后在启动其它外部的程序,这样外部的程序就会使用我修改后的变量内容,如下:
说明:在Perl修改%ENV哈希中的值并不会影响shell或者其它父进程。 用反引号捕捉输出结果不管system还是exec函数调用,被调用程序的输出都会定向到Perl的标准输出。如果我们对调用程序的输出感兴趣且要进行下一步处理的话,可以使用反引号来代替单引号或双引号:
my
$now
=
`date`
;
# 捕获date的输出
print "The time is now $now" ; # 这里不需要换行符,因为date的输出里已经包含 这个反引号就是ESC键下面的那个按键。如果懂得shell脚本的话就明白了,它和shell脚本中的应用类似,但有一点不同,shell会将输出的换行符去掉,但Perl则不会。因此我们经常的做法是使用chomp命令做一下处理:
chomp
(
my
$no_newline_now
=
`date`
)
;
print "A moment ago,it was $no_newline_now,I think.n" ; Perl解释反引号里面的值的方式类似于system的单参数形式,并且在解释器中会以双引号字符串形式展开,这意味着反斜线转移与变量内插都会正常处理。下面的例子要去的一系列Perl函数的说明文档,可以重复执行perldoc命令,每次使用不同的参数:
说明:每次循环执行时$_的值都会不同,这样每次就可以执行不同的命令并得到他的输出。 在列表上下文中使用反引号 如果命令会输出很多行,在标量上下文中使用反引号会得到一个很长的文本串,其中包含换行符,然而在列表上下文中同样的反引号调用则返回输出的文本行列表。
●这里用三次循环覆盖以上的数据库,这里用了正则表达式进行匹配,但并没有明确使用绑定操作符(=~),而是直接针对$_进行匹配。这样写更简洁。 将进程视为文件句柄 到目前为止我们看到的都是由Perl同步控制子进程:启动一个命令,然后等着它结束,或者获得其输出,实际上Perl可以启动一个异步运行的子进程,并和它保持通信,直到子进程终止。
open DATE
,
"date|"
or
die
"cannot pipe from date: $!"
;
open MAIL , "|mail merlyn" or die "cannot pipe to mail: $!" ; 其实上例很好理解,如果管道符放在后面代表命令的输出放到了文件句柄中(该句柄只读),管道符在后面则代表需要往句柄中写入信息(该句柄只写)。如果无法创建子进程open就会失败,但不会立即报错,只有在关闭文件句柄时才会报错。 总之可以假设这些文件句柄都连接了一种虚幻的文件,一个包含了date命令的输出内容,另一个则可以自动用mail命令发送邮件。
close MAIL
;
die "mail:non-zero exit of $?" if $? ; 注意这里的$?变量和shell中的是一致的,0为正常退出非零为错误。它指示上一条命令是否正常退出。 下面要考虑的问题:为什么要使用文件句柄的方式来和进程打交道呢?如果就像得到进程的输出来做进一步的处理,那用反引号无疑是最简洁快速的方式。然而如果子进程的输出是间断性的是一个输出的过程的话,那就不需要用这种文件句柄的方式了。另外还有一点就是子进程的异步,这个在前文已经说过了。来看一下使用find命令查找指定文件,再用perl格式化输出的例子:
#!/usr/bin/perl -w
use strict ; open F , "find . -atime +90 -size +1b -print|" or die "fork: $!" ; while ( ) { chomp ; printf "%s size %.2fK last accessed on %sn" , $_ , ( - s $_ ) / 1024 , -A $_ ; } --find命令这次运行时要查找那些90天内未被访问过超过1kb的文件,这个find过程是一个连续的过程,如果用反引号来运行的话,程序要等到都查找完了之后才能放到一个变量中然后使用循环读取,而使用文件句柄就可以找到一个文件,然后就格式化输出文件。改程序中利用了Perl笔记10中介绍的文件测试命令。 发送及接收信号linux/unix中针对进程的信号有很多,如果对shell了解的话大家都应该清楚。下面是man kill看到的说明,只挑选了简单几个常用的:
信号可以是系统发给进程的,也可以是进程发给进程的。因此我么可以编写Perl程序来给别的进程发信号,前提就是必须知道目标进程的ID。假如知道了目标进程的ID为4201,则可以通过下面的语句来发送信号:
对特殊哈希%SIG进行赋值就能设置信号处理程序。哈希键是信号名称,这里不用写固定的前缀SIG。哈希的值是子程序名,注意,子程序不用写“与号”。现在只要收到SIGINT信号,Perl就会将程序转到信号处理程序,这里的子程序会清理临时文件并退出。程序的末尾也有调用了清理子程序。 如果INT信号的处理程序没有退出操作,而是直接返回,那么用户按的Ctrl+C 就没有效果了。程序仍然会运行下去。有些时候我们需要的就是这种操作,也就是说我们利用信号处理程序处理一些任务之后,不退出,然后接着做下面的工作。下面的例子,假设处理文件里的每行都要花费很长时间,而你想要在收到信号时停止处理,却不想让等待中的这一行中断,这时,只要在信号处理程序中设置一个标记,然后在每行处理结束时检查它即可:
本章练习 1、写一个程序,它会进入某个特定的目录,比如系统根目录。然后执行ls -l命令获得该目录内容的详细报告。如果非unix系统,请使用该系统上相应命令去的详细列表。
执行:perl ex_14_1.pl ~ 2、接上面的程序,让它将命令的输出送到当前目录下的ls.out 文件,错误暑促则送到 ls.err文件。
3、写依程序,它会解析date命令的输出以判断今天是星期几。如果是工作日,则输出get to work,否则输出go play。
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |