科技讯息网 – 程序员的那点事!

首页 > 编程资料 > Perl语言 > 正文

perl常问问题集--第六篇

浏览次数:次 2006年04月12日 作者:keigopan 字号:

如何得知使用者正在哪个作业系统下执行我的?perl?程式??
$^O?这个变数(若使用?English?模组就是?$OSTYPE)会指出你的?perl?解译器执?行档是替哪个作业系统、平台所建的。?


--------------------------------------------------------------------------------?

为什麽?exec()?不会传值回来??
因为这正是它所做的:它用另一个不同的程式来取代你当时所执行的。如果你的程?式需要继续跑下去(这可能正是你问此问题的原因吧?),改用?system()?。?


--------------------------------------------------------------------------------?

如何对?键盘/萤幕/滑鼠?做些花样??
连接/控制?键盘、萤幕和指标装置(「滑鼠」)的方法因作业系统的不同而有不?同;不妨试试下列模组:?

键盘?
Term::Cap?perl?标准内建模组?
Term::ReadKey?CPAN?
Term::ReadLine::Gnu?CPAN?
Term::ReadLine::Perl?CPAN?
Term::Screen?CPAN?

萤幕?
Term::Cap?perl?标准内建模组?
Curses?CPAN?
Term::ANSIColor?CPAN?

滑鼠?
Tk?CPAN?


--------------------------------------------------------------------------------?

如何向使用者询问密码??
(这个问题跟全球资讯网一点关系也没有。如果你要找的是跟?WWW?有关的,那就?看另一份常见问题集吧。)?

【译注:中文版的?Perl?CGI?程式设计常见问题集可以在下列网址中找到:?http://www.math.ncu.edu.tw/~chenym/FAQ/Perl/perl-cgi-faq/?
http://2tigers.net/perl/perl-cgi-faq-chi/?】?

在?crypt?里面有个范例。首先,将你的终端机设为「无回应」[no?echo]?模式,然後就用平常的方法将密码读入。你可以用老式的?ioctl()?函数、?POSIX?终端机控制函数(参看?POSIX?,和?Camel?书第七章),或是呼叫?stty?程式,这些方法的可携性/移植性程度都不一样。?

你也可以在大部份系统上使用?CPAN?里的?Term::ReadKey?模组,这个模组较易使?用而且理论上也较据可携性/移植性。?


--------------------------------------------------------------------------------?

如何对序列埠做读写动作??
这端看你在什麽作业系统上执行你的程式。以?Unix?来说,序列埠可以透过?/dev?目录下的档案来撷取;?而在其他系统上,设备的名称无疑地会不一样。以下是一些?在设备互动时可能遭遇的共同问题:?

锁档?(lockfiles)?
你的系统可能会使用锁档来控制多重读写的情况。确定你用的是正确的协定。因为?当多个程序同时对一个装置做读取时可能会发生意想不到的情况。?
开档模式?
如果你打算对一个装置同时做读与写的动作,你得将它开到更新的模式(?在?open?里有更详细的解说)。如果你不希望冒着阻挡其他程序读取?这个装置的风险,那就得用?sysopen()?和?Fcntl?模组(标准?perl?的一部分)内?的?O_RDWR|O_NDELAY|O_NOCTTY。在?sysopen?里有对此方法更?详尽的解说。?
档案尾?
有些装置会等着在每行结尾处看到一个?``\r'',而非?``\n''。在某些平台上的?perl,?``\r''和?``\n''?与它们平常(在?Unix?上)所指的?ASCII?值?``\015''?和?``\012''?有?所不同。你也许得直接给定数值,例如用八进位?(``\015'')、十六进位?(``0x0D''),?或指定控制字元?(``\cM'')。?
print?DEV?"atv1\012";?#?对某些装置来说是错误的?
print?DEV?"atv1\015";?#?对某些装置来说是对的?

尽管对普通的文字档案,一个?``\n''?便可解决断行的问题,但目前在不同作业系统?间(Unix、DOS/Win?和?Macintosh),对於断行记号仍无统一标准,而只有用?``\015\012''?来当成?每行的结尾,然後再视需要去掉输出中不想要的部份。这?个做法尤其常用於?socket输出/输入?与自动洗清?(autoflushing),也是接下来?要讨论的主题。?

洗清输出?
如果你希望?print()?的时候每个字元都要送到你指定的装置去,那你应自动清洗?你的档案把手,旧方法是:?
use?FileHandle;?
DEV->;autoflush(1);?

比较新的方法是:?

use?IO::Handle;?
DEV->;autoflush(1);?

你可以用?select()?和?$|?变数来控制自动清洗的动作(参考?$|?和select?):?

$oldh?=?select(DEV);?
$|?=?1;?
select($oldh);?

你也可能看到不使用额外的暂存变数的写法,例如:?

select((select(DEV),?$|?=?1)[0]);?

如同前一个项目所说的,这方法对?Unix?和?Macintosh?间的?socket?输出/入?没?用。在这种情况下,你得把你的行末字元写死在程式码内。?

不挡式输入?(non-blocking?input)?
如果你正在做一个具阻挡性的?read()?或?sysread()?动作,则你需要安排一个闹?铃把手或提供一个逾时设定(参看?alarm)。如果你是用非阻挡式的?开档,那麽就要配合非阻挡性的读取,也就是说得用到4?个参数的?select()?来确?定此装置的?输出/入?是否已准备好了(参考?select?)。?

--------------------------------------------------------------------------------?

如何逆解加密後的密码档案??
花大把大把的钱去买破解专用的硬体,这会让你成为焦点话题。?

说正经的,如果是碰到?Unix?密码档的话就不行?-?Unix?密码系统用的是单向的加?密函数。像?Crack?之类的程式可以暴力地(并聪明地)试着猜出密码,但无法?(也不能)保证速战速决。?

如果你耽心的是使用者选取不良的密码,你应该在使用者换密码时主动审核(例如?说修改?passwd(1)?程式加入这个功能)。?


--------------------------------------------------------------------------------?

如何启动一个背景执行的程序??
你可以使用:?

system("cmd?&")?

或是用?fork,像?fork?里写的(在?perlipc?里有更进一步的?范例)。如果你在?Unix?类的系统上的话,请注意以下几件事情:?

STDIN,?STDOUT?和?STDERR?是共享的?
主程序和背景程序(即「子」程序)共用同一个?STDIN、STDOUT?和?STDERR?档案?把手。如果两个程序想同时去读、写同一个档案把手,就可能有怪事会发生。你也?许应该替子程序关闭或重新开启这些把手。你可以用开启一个管道?(pipe)?的方法?避免这些问题(参看?open)但是在某些系统上这样做会强迫子程序?必须比父程序早死。?
讯号?
SIGCHLD、可能还有?SIGPIPE?这两个讯号要抓到。当背景程序执行完成後就会送出?SIGCHLD?讯号。而当你写入一个子程序已经关闭的档案把手时就会收到?SIGPIPE?讯号(一个未抓住的?SIGPIPE?可能导致你的程式无声无息地死去)。用?system("cmd&")?的话不会有这样的问题。?
僵?程序?
你得做准备,在子程序结束时「收成」它:?
$SIG{CHLD}?=?sub?{?wait?};?

在?Signals?有范例程式教你怎麽做。用?system("prog?&")?的?话不会有僵?程序的问题。?


--------------------------------------------------------------------------------?

如何捕捉?控制字元/讯号??
你并不能真的?``捕捉''?一个控制字元。而是控制字元产生一个讯号让你捕捉。关於?讯号的资料可以在?Signals?以及?Camel?书第六章里找到。?

要小心的是,大多?C?程式库无法重新进入?[re-entrant]。因此当你要尝试着在一?个处理器里做?print()?动作,而这个处理器是由另一个stdio?的动作所叫出来的?话,你的内部结构可能会处於失调状态,而程式可能会丢出记忆核心?(dump?core)。?有的时候你可以用?syswrite()?取代?print()?以避免这个状况。?

除非你极为小心,否则在一个讯号处理器中,唯一安全可做的是:设定一个变数後?离开。而在第一个情况下,你在设定变数的时候应确定?malloc()?不会被叫出来?(譬如,设定一个已经有值的变数)。?

例如:?

$Interrupted?=?0;?#?确定它有个值?
$SIG{INT}?=?sub?{?
$Interrupted++;?
syswrite(STDERR,?"哇\n",?5);?
}?

然而,因为系统呼叫会自己重新启动,你将会发现如果你用的是「慢的」呼叫,像?、read()、connect()?或?wait(),那麽将它们停下的唯一办法是使?用?「跳远」的方式跳出来;也就是产生一个例外讯号。参看在?Signals?里对阻挡性?flock()?的逾时处理器的说明,或骆驼书第六?章。?


--------------------------------------------------------------------------------?

如何更动?Unix?系统上隐式密码档?(shadow?password)?的内容??
如果你的?perl?安装正确的话,在?perlfunc?里描述的?getpw*()?函数应该就?能够读取隐式密码档了(只有读取权)。要更动该档案内容,做一个新的密码档?(这个档案的格式因系统而异,请看?passwd(5)?)然後用?pwd_mkdb(8)(参考?pwd_mkdb(5))来安装新的密码档。?


--------------------------------------------------------------------------------?

如何设定时间和日期??
假设你有足够的权限,你应该可以用?date(1)?程式来设定系统的时间与日期。?(但没有针对个别程序修改时间日期的方法)这机制在?Unix、MS-DOS、Windows?和?NT?下都能用;VMS?下则要用?set?time?。?

然而,如果你只是要更动你的时区,只消设定一个环境变数即可:?

$ENV{TZ}?=?"MST7MDT";?#?unix?下?
$ENV{'SYS$TIMEZONE_DIFFERENTIAL'}="-5"?#?vms?
system?"trn?comp.lang.perl";?


--------------------------------------------------------------------------------?

如何能够针对小於一秒的时间做?sleep()?或?alarm()?的动作呢??
如果你要比?sleep()?所提供的最小单位一秒更精细的话,最简单的方法就是用?select?里面写的?select()?函数。如果你的系统有?itimers?并支?援syscall(),你可以试试下面这个老范例?http://www.perl.com/CPAN/doc/misc/ancient/tutorial/eg/itimers.pl?.?


--------------------------------------------------------------------------------?

如何测量小於一秒的时间??
一般来说,你可能做不到。?Time::HiRes?模组(CPAN?有)在某些系统上能达到此?功能。?

总之,你可能做不到。但是如果你的?Perl?支援?syscall()?函数并支援类似?gettimeofday(2)?的系统呼叫,你也许可以这麽做:?

require?'sys/syscall.ph';?

$TIMEVAL_T?=?"LL";?

$done?=?$start?=?pack($TIMEVAL_T,?());?

syscall(?&SYS_gettimeofday,?$start,?0))?!=?-1?
or?die?"gettimeofday:?$!";?

##########################?
#?在这做你要做的事?#?
##########################?

syscall(?&SYS_gettimeofday,?$done,?0)?!=?-1?
or?die?"gettimeofday:?$!";?

@start?=?unpack($TIMEVAL_T,?$start);?
@done?=?unpack($TIMEVAL_T,?$done);?

#?fix?microseconds?
for?($done[1],?$start[1])?{?$_?/=?1_000_000?}?

$delta_time?=?sprintf?"%.4f",?($done[0]?+?$done[1]?)?
-?
($start[0]?+?$start[1]?);?


--------------------------------------------------------------------------------?

如何做?atexit()?或?setjmp()/longjmp()?的动作?(例外处理)?
第五版的?Perl?增加了?END?区块,可以用来模拟?atexit()的效果。当程式或执行?绪(thread)?终了时就会去呼叫该包装的?END?区块(参考?perlmod?文件)。但?是如果当程式被没有抓到的讯号终结了,END?区块就不会被呼叫到,所以当你用?END?时应再加上?

use?sigtrap?qw(die?normal-signals);?

Perl?的例外处理机制就是它的?eval()?运算子。你可以把?eval()?当做?setjmp?而die()当做?longjmp?来使用。更详细的说明请参考?Signals?和?Camel书第六章里关於讯号的那段,尤其是描述有关?flock()?的逾时处理器那段。?

如果你只对例外处理的部分有兴趣,试试?exceptions.pl?程式库(包含在标准?perl里)。?

如果你要的是?atexit()?语法(以及?rmexit()),试试?CPAN?里的?AtExit?模组。?


--------------------------------------------------------------------------------?

为何我的?sockets?程式在?System?V?(Solaris)?系统下不能用?「不支援本协定」这个错误讯息又是什麽意思??
有些?Sys-V?根底的系统,特别像?Solaris?2.X,已重新将一些标准的?socket常数?定义过了。由於这些常数在各种架构下都是定值,所以在?perl程式码中常被人写?死在里面。处理此问题的适当方式?是用?``use?Socket''?来取得正确的值。?

须注意尽管?SunOS?和?Solaris?在二进位执行档上相容,这些值是相异的。自己去?想为什麽吧。?


--------------------------------------------------------------------------------?

如何从?Perl?里呼叫系统中独特的?C?函数??
通常是写个外部的模组来处理?-?参看「我要如何学到将?C?与?Perl?连结在一起??[h2xs,?xsubpp]」?这问题的答案。然而,如果此函数是个系统呼叫,而你的系统?有支援?syscall(),那麽可以用?syscall?函数(说明在?perlfunc?里)。?

切记先查查看你的?perl?版本中所附的模组以及?CPAN?里的模组,因为也许某人已?经写了个这样的模组。?


--------------------------------------------------------------------------------?

在哪里可以找引入档来做?ioctl()?或?syscall()??
以前这些档案会由标准?perl?发行中所附的?h2ph?工具来产生。这个程式将?C?标?头档案里的?cpp(1)指令转换成内含副程式定义的档案,像?&SYS_getitimer,你可?以把它当做函数的参数。这样做并不怎麽完美,但通常可达成任务。简单的像?errno.h?、syscall.h?和socket.h?这些档案都没问题,但像?ioctl.h?这种较难的档案总是需要人工编辑。以下是安装?*.ph?档案的步骤:?

1.?进入最高使用者帐户?
2.?cd?/usr/include?
3.?h2ph?*.h?*/*.h?

如果你的系统支援动态载入,那麽为了可携性、而且合理的做法是使用?h2xs(也?是?perl的标准配备)。这个工具将?C?标头档案转换成?Perl?的衍伸档案?(extensions)。?h2xs?的入门要看?perlxstut?。?

如果你的系统不支援动态载入,你可能仍应使用?h2xs。参看?perlxstut?和?MakeMaker?(简单来说,就是用?make?perl?、而非?make来重?建一份使用新的静态连结的?perl)。?


--------------------------------------------------------------------------------?

为何?setuid?perl?程式会抱怨关於系统核心的问题??
有些作业系统的核心有臭虫使得?setuid?程式在先天上就不安全。Perl提供你一些?方法(在?perlsec?里有写)可跳过这些系统的缺陷。?


--------------------------------------------------------------------------------?

如何打开对某程式既输入又输出的管道?(pipe)??
IPC::Open2?模组(perl?的标准配件)是个好用的方法,它在内部是藉着pipe()、?fork()?和?exec()?来完成此工作。不过切记要读它文件里关於锁死的警告?(?Open2?)。?


--------------------------------------------------------------------------------?

为何用?system()?却得不到一个指令的输出呢??
你把?system()?和反向引号?(``)?的用法搞混了。?system()?会执行一个指令然後?传回指令结束时的状况资讯(以一个?16?进位值表示:低位元是程序中止所收到的?讯号,高位元才是真正离开时的传回值)。反向引号?(``)?执行一个指令并且把它?所送出的东西送到?STDOUT。?

$exit_status?=?system("mail-users");?
$output_string?=?`ls`;?


--------------------------------------------------------------------------------?

如何补捉外部指令的?STDERR??
有叁种基本方式执行外部指令:?

system?$cmd;?#?使用?system()?
$output?=?`$cmd`;?#?使用?反向引号?(``)?
open?(PIPE,?"cmd?|");?#?使用?open()?

在?system()?下,STDOUT?和?STDERR?都会输出到和?script?本身的?STDOUT,?STDERR相同的出处,除非指令本身将它们导向它处。反向引号和?open()?则?只?读取指令的?STDOUT?部份。?

在上述方法中,你可以在呼叫前更改档案描述元?(file?descriptor)?名称:?

open(STDOUT,?">;logfile");?
system("ls");?

或者使用?Bourne?shell?的档案描述元重导功能:?

$output?=?`$cmd?2>;some_file`;?
open?(PIPE,?"cmd?2>;some_file?|");?

也可以用档案描述元重导功能将?STDERR?导向到?STDOUT:?

$output?=?`$cmd?2>;&1`;?
open?(PIPE,?"cmd?2>;&1?|");?

注意你?不能?光是将?STDERR?开成?STDOUT?的复制,而不呼叫?shell来做这个?重导的工作。这样是不行的:?

open(STDERR,?">;&STDOUT");?
$alloutput?=?`cmd?args`;?#?stderr?仍然会跑掉?

失败的原因是,open()?让?STDERR?在呼叫?open()?时往?STDOUT的方向走。然後反?向引号让?STDOUT的内容跑到一个字串变数里,但是没有改变?STDERR?的去向(它?仍然往旧的?STDOUT那里跑)。?

注意,在反向引号里你?必须?使用?Bourne?shell?(sh(1))?重导的语法而非?csh(1)的!至於为何?Perl?的?system()、反向引号和开管道都用?Bourne?shell语?法的原因,可在下址找到:?http://www.perl.com/CPAN/doc/FMTEYEWTK/versus/csh.whynot?

你也可以使用?IPC::Open3?模组(perl?标准配备),但注意它的参数顺序和?IPC::Open2不一样(参看?Open3?)。?


--------------------------------------------------------------------------------?

为何当管道开启失败时?open()?不会传回错误讯息??
其实会,只是或许并非以你期望的方式。在遵循标准?fork()/exec()?机制的系统?上(例如,Unix),运作原理是这样的:open()?导致一个?fork()。在父程序里,?open()传回子程序的ID。然後子程序?exec()?从管道传来/出?的指令。父程序无?法得知?exec()?的动作成功与否-它能传回的只有?fork()?动作成功与否的消息。?要找出这指令是否顺利执行,你得补捉?SIGCHLD讯号并?wait()?以得到子程序离开?时的状态。如果你要写资料到子程序,则?SIGPIPE也该一并捕捉-否则在你写入之?前可能无法察觉?exec()?动作已失败了。这些在?perlipc?文件里都有说明。?

在使用?spawn()?机制的系统里,open()?也许?能达到你所期望的-除非?perl?使用一个?shell?来起始你的指令。在这情况下以上对?fork()/exec()?的描述仍适?用。?


--------------------------------------------------------------------------------?

在输出值是空的情境里使用反向引号有何不对??
严格说起来,没啥不对。但从程式写作严谨与否来说,这样无法写出较易维护的程?式码,因为反向引号有一个(可能很巨大的)传回值,而你却忽略它。同时这也是?缺乏效率的方法,因为你得把每行所有的输出读进来、留一块记忆体给它们,然後?再把它们丢开。人们常常做下列这种事:?

`cp?file?file.bak`;?

然後它们就会想:「嘿,乾脆以後都用反向引号来执行程式好了。」这是馊主意,?因为反向引号的目的在补捉程式的输出;system()?函数才是用来执行程式的。?

再看看下列这一行:?

`cat?/etc/termcap`;?

你还没有指定输出,所以它会浪费记忆体(就那麽一下子)。另外你也忘了检查?$??看看程式是否正确的执行。即使你写成?

print?`cat?/etc/termcap`;?

但在大部份情况下,这本来可以、而且也应该写成?

system("cat?/etc/termcap")?==?0?
or?die?"cat?program?failed!";?

这样可快速地得到输出(一产生出来就会得到,不用等到最後),并且检查传回值。?

system()?同时具有直接决定是否先做?shell?万用字元?(wildcard)处理的功能,?反向引号就不行。?


--------------------------------------------------------------------------------?

如何不经过?shell?处理来呼叫反向引号??
这需要些技巧。本来是写成?

@ok?=?`grep?@opts?'$search_string'?@filenames`;?

你得改成:?

my?@ok?=?();?
if?(open(GREP,?"-|"))?{?
while?()?{?
chomp;?
push(@ok,?$_);?
}?
close?GREP;?
}?else?{?
exec?'grep',?@opts,?$search_string,?@filenames;?
}?

一如?system(),当你?exec()?一个序列时不会有?shell?解译的情况发生。?


--------------------------------------------------------------------------------?

为何给了?EOF(Unix?上是?^D,MS-DOS?上是?^Z)後我的程式就不能从?STDIN?读取东西了呢??
因为某些?stdio?的?set?error?和?eof?旗标需要清除。你可以用?POSIX?模组里定?义的clearerr()。这是在技术上正确的解决之道。还有一些较不保险的方法:?

试着保存搜寻指标然後去找它,例如:?
$where?=?tell(LOG);?
seek(LOG,?$where,?0);?

如果那样行不通,试着去?seek()?档案的另一部份然後再找回来。?
如果还是行不通,试着?seek()?档案另一个相异的的部份,读点东西,再回去找。?
如果依然不行,放弃使用?stdio?改用?sysread。?

--------------------------------------------------------------------------------?

如何把?shell?程式转成?perl??
学习?Perl?然後重写。说真的,没有简单的转换方式。用?shell?做起来很笨的工?作可以用?Perl?很轻松的做到,而就是这些麻烦之处使得?shell->;perl?转换程式?非常不可能写得出来。在重新撰写程式的过程里,你会认清自己真正要做的工作为?何,也希望能够跳脱?shell?的管线资料流机制?[pipeline?datastream?paradigm],?这东西虽对某些事情很方便,但也常造成低效率。?


--------------------------------------------------------------------------------?

perl?能处理?telnet?或?ftp?这种双向互动吗??
试试?Net::FTP、TCP::Client?和?NET::Telnet?模组(CPAN?有)。?http://www.perl.com/CPAN/scripts/netstuff/telnet.emul.shar也有助於模拟?telnet?协定,但是?Net::Telnet?可能较容易使用。?

如果你所要做的只是假装?telnet?但又不要起始?telnet?时的沟通程序,那麽以下?这个标准的双程序方式就可以满足你的需要了:?

use?IO::Socket;?#?5.004?才有的新模组?
$handle?=?IO::Socket::INET->;new('www.perl.com:80')?
||?die?"无法接上?www.perl.com?的?port?80:?$!";?
$handle->;autoflush(1);?
if?(fork())?{?#?XXX:?undef?表示失败?
select($handle);?
print?while?;?#?将所有从?stdin?来的丢到?socket?
}?else?{?
print?while?;?#?将所有?socket?来的丢到?stdout?
}?
close?$handle;?
exit;?


--------------------------------------------------------------------------------?

如何在?Perl?里达到?Expect?的功能??
很久很久以前,有个叫做?chat2.pl?的程式库(perl?标准配备之一),但一直没?真正完工。现在,你的最佳选择就是从?CPAN?来的?Comm.pl?程式库。?


--------------------------------------------------------------------------------?

有没有可能将?perl?的指令列隐藏起来,以躲避像?"ps"?之类的程式??
首先要注意的是,如果你的目的是为了安全(例如避免人们偷看到密码),那你应?该重写你的程式,把重要的资讯从参数中剔除。光是隐藏起来不会让你的程式变得?完全安全。?

如要真的把看得见的指令列改掉,你可以设定?$0?这个变数值,如同?perlvar?里写的。但这方法并非各种作业系统都适用。像?sendmail之类的背景程式?(daemons)?就将它们的状态放在那儿:?

$0?=?"orcus?[accepting?connections]";?


--------------------------------------------------------------------------------?

我在?perl?script?里?{更动目录,更改我的使用环境}。为何这些改变在程式执行完後就消失了呢?如何让我做的修改显露出来??
Unix?
严格的说起来,这是做不到的-一个?script?的执行是从启动它的?shell?生出一?个不同的程序来执行。这个程序的任何变动不会反映到它的父程序,只会反映到更?改之後它自己创造出来的子程序。有个?shell?魔术可以让你藉着在?shell?里?eval()你?script?的输出来装出这种效果,在?comp.unix.questions?FAQ?里有详?细内容。?
VMS?
对?%ENV?的更改会持续到?Perl?离开,但是目录更动则不会。?

--------------------------------------------------------------------------------?

如何关闭一个程序的档案把手而不用等它完成呢??
假设你的系统支援这种功能,那就只要送个适当的讯号给此程序(参看?kill)。通常是先送一个?TERM?讯号,等一下下,然後再送个?KILL?讯号去终结它。?


--------------------------------------------------------------------------------?

如何?fork?出一个背景执行?(daemon)?程序??
如果你所指的是离线的程序(未与?tty?连线者),那下列的程序据说在大部份的?Unix系统都能用。非?Unix?系统的使用者应该检查?Your_OS::Process?模组看看有?没有其他的解决方案。?

打开?/dev/tty?然後对它用?TIOCNOTTY?ioctl。请参考?tty(4)?。?
把目录换到?/?
重开?STDIN、STDOUT?和?STDERR?使它们不会与旧的?tty?连接。?
用下列方法把程式丢到背景:?
fork?&&?exit;?


--------------------------------------------------------------------------------?

如何使我的程式和?sh?及?csh?一起执行??
参看?eg/nih?这?script(perl?原始码发行的一部分)。?


--------------------------------------------------------------------------------?

如何得知我是否正在互动模式下执行??
问得好。有的时候?-t?STDIN?和?-t?STDOUT?可以提供线索,有时不行。?

if?(-t?STDIN?&&?-t?STDOUT)?{?
print?"Now?what??";?
}?

在?POSIX?系统中,你可以用以下方法测试你自己的程序群组与现在控制你终端机?的是否相同:?

use?POSIX?qw/getpgrp?tcgetpgrp/;?
open(TTY,?"/dev/tty")?or?die?$!;?
$tpgrp?=?tcgetpgrp(TTY);?
$pgrp?=?getpgrp();?
if?($tpgrp?==?$pgrp)?{?
print?"前景\n";?
}?else?{?
print?"背景\n";?
}?


--------------------------------------------------------------------------------?

如何让一个缓慢的事件过时??
如同?Signals?和?Camel?书第六章里所描述的,用?alarm()?函数,?或许再配合上一个讯号处理器。你也可以改用?CPAN?里更具弹性的?Sys::AlarmCall?模组来做。?


--------------------------------------------------------------------------------?

如何设定?CPU?使用限制??
使用?CPAN?里的?BSD::Resource?模组。?


--------------------------------------------------------------------------------?

在?Unix?系统上如何避免产生僵?程序?(zombies)??
使用?Signals?里面叫?reaper?的程式码,在接到?SIGCHLD?时会呼?叫wait(),或是用?fork?里面写的双?fork?技巧。?


--------------------------------------------------------------------------------?

如何使用一个?SQL?资料库??
有几个连接?SQL?资料库非常好的界面。参看?http://www.perl.com/CPAN/modules/dbperl/DBD?里的?DBD::*?模组。?


--------------------------------------------------------------------------------?

如何让?system()?在收到?control-C?後就离开??
做不到。你需要摹仿?system()?呼叫(参看?perlipc?里的范例程式),然後设计一个讯号处理器,让它把?INT?讯号传给子程序。?


--------------------------------------------------------------------------------?

如何开启一个档案但不阻挡其他程序的阅读??
如果你有幸使用到支援非阻挡性读取的系统(大部份?Unix?般的系统都有支援),?你只需要用?Fcntl?模组里的?O_NDELAY?或?O_NONBLOCK?旗标,配合?sysopen():?

use?Fcntl;?
sysopen(FH,?"/tmp/somefile",?O_WRONLY|O_NDELAY|O_CREAT,?0644)?
or?die?"can't?open?/tmp/somefile:?$!";?


--------------------------------------------------------------------------------?

如何安装一个?CPAN?模组??
最简单的方法就是让?CPAN?这个模组替你代劳。这个模组包含在?5.004及以後的版?本中。如要手动安装?CPAN?模组,或是任何按规矩发展的?CPAN模组,遵循以下步?骤:?

把原始码解开放到一个暂存区域?
perl?Makefile.PL?

make?

make?test?

make?install?

如果你用的?perl?版本在编译时没有建入动态连结的功能,那你只消把第叁步?(make)换成?make?perl?然後你就会得到一个新的?perl?执行档,里头连?有你新加入的延伸。?

在?MakeMaker里面有更多关於建构模组的细节,并参考「如何保有?一份自己的?模组/程式库目录?」这个问题。?


--------------------------------------------------------------------------------?

如何保有一份自己的?模组/程式库?目录??
当你建构模组时,在产生?Makefiles?时使用?PREFIX?选项:?

perl?Makefile.PL?PREFIX=/u/mydir/perl?

然後在执行用到此?模组/程式库?的程式前先设好?PERL5LIB?环境变数(参考?perlrun?),或是用?

use?lib?'/u/mydir/perl';?

进一步的资料可在?Perl?的?lib?手册中找到。?


--------------------------------------------------------------------------------?

如何把我的程式所在位置加入?模组/程式库?搜寻路径??
use?FindBin;?
use?lib?"$FindBin:Bin";?
use?your_own_modules;?


--------------------------------------------------------------------------------?

如何在执行时添加目录到自己的引入路径中??
以下是我们建议更动引入路径的方法:?

PERLLIB?环境变数?
PERL5LIB?环境变数?
perl?-Idir?指令列参数?
use?lib?pragma,?as?in?
use?lib?"$ENV{HOME}/myown_perllib";?

後者特别有用,因为它知道与机器相关的架构。lib.pm?机制模组是从?5.002?版开?始包含在?Perl?里面的。?


--------------------------------------------------------------------------------?

如何从终端机一次抓进一个按键?如果用?POSIX?模组时又该怎麽做??
#!/usr/bin/perl?-w?
use?strict;?
$|?=?1;?
for?(1?
exit;?

BEGIN?{?
use?POSIX?qw(:termios_h);?

my?($term,?$oterm,?$echo,?$noecho,?$fd_stdin);?

$fd_stdin?=?fileno(STDIN);?

$term?=?POSIX::Termios->;new();?
$term->;getattr($fd_stdin);?
$oterm?=?$term->;getlflag();?

$echo?=?ECHO?|?ECHOK?|?ICANON;?
$noecho?=?$oterm?&?~$echo;?

sub?cbreak?{?
$term->;setlflag($noecho);?
$term->;setcc(VTIME,?1);?
$term->;setattr($fd_stdin,?TCSANOW);?
}?

sub?cooked?{?
$term->;setlflag($oterm);?
$term->;setcc(VTIME,?0);?
$term->;setattr($fd_stdin,?TCSANOW);?
}?

sub?getone?{?
my?$key?=?'';?
cbreak();?
sysread(STDIN,?$key,?1);?
cooked();?
return?$key;?
}?

}?
END?{?cooked()?}



?轩辕砍刀 回复于:2003-05-01 16:47:12

看完一篇顶一篇


?b2linux 回复于:2006-04-12 16:44:30

受不了啦!