Username: Password:

perl常问问题集--第六篇
来源:linux宝库作者:linux宝库 发布时间:2007-09-30 00:00:00


  怎样得知使用者正在哪个作业系统下执行我的 perl 程式?

  $^O 这个变数(若使用 English 模组就是 $OSTYPE)会指出您的 perl 解译器执 行档是替哪个作业系统、平台所建的。

  --------------------------------------------------------------------------------

  为什麽 exec() 不会传值回来?

  因为这正是他所做的:他用另一个不同的程式来取代您当时所执行的。假如您的程 式需要继续跑下去(这可能正是您问此问题的原因吧?),改用 system() 。

  --------------------------------------------------------------------------------

  怎样对 键盘/萤幕/滑鼠 做些花样?

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

  键盘

  Term::Cap perl 标准内建模组

  Term::ReadKey CPAN

  Term::ReadLine::Gnu CPAN

  Term::ReadLine:erl 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((参考 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:rocess 模组看看有 没有其他的解决方案。

  打开 /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() }

喜欢本文,那就收藏到:

    Del.icio.us Google书签 Digg Live Bookmark Technorati Furl Yahoo书签 Facebook 百度搜藏 新浪ViVi 365Key网摘 天极网摘 和讯网摘 博拉网 POCO网摘 添加到饭否 QQ书签 Digbuzz我挖网
相关评论  我也要评论
还没有关于此文章的相关评论!
  • 昵称: (为空则显示guest)
  • 评论分数: ★ ★ ★★★ ★★★★ ★★★★★
  • 评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
  • 导航
    赞助商
    文章类别
    订阅