• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • perl常問問題集--第六篇

    發表于:2007-06-11來源:作者:點擊數: 標簽:
    如何得知使用者正在哪個作業系統下執行我的 perl 程式? $^O 這個變數(若使用 English 模組就是 $OSTYPE)會指出你的 perl 解譯器執 行檔是替哪個作業系統、平臺所建的。 為什麼 exec() 不會傳值回來? 因為這正是它所做的:它用另一個不同的程式來取代你當

    如何得知使用者正在哪個作業系統下執行我的 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 有關的,那就 看另一份常見問題集吧。)

    【譯注:中文版的 PerlCGI 程式設計常見問題集可以在下列網址中找到: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);
     }
    

    然而,因為系統呼叫會自己重新啟動,你將會發現如果你用的是「慢的」呼叫,像 <FH>、read()、connect() 或wait(),那麼將它們停下的唯一辦法是使 用 「跳遠」的方式跳出來;也就是產生一個例外訊號。參看在Signals 里對阻擋性flock() 的逾時處理器的說明,或駱駝書第六 章。


    如何更動 Unix 系統上隱式密碼檔 (shadow password) 的內容?

    如果你的 perl 安裝正確的話,在perlfunc 里描述的 getpw*() 函數應該就 能夠讀取隱式密碼檔了(只有讀取權)。要更動該檔案內容,做一個新的密碼檔 (這個檔案的格式因系統而異,請看passwd(5) )然後用pwd_mkdb(8)(參考 pwd_mkdb(5))來安裝新的密碼檔。


    如何設定時間和日期?

    假設你有足夠的權限,你應該可以用date(1) 程式來設定系統的時間與日期。 (但沒有針對個別程序修改時間日期的方法)這機制在 Unix、MS-DOS、WindowsNT 下都能用;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.hsocket.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 (<GREP>) {
     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()。這是在技術上正確的解決之道。還有一些較不保險的方法:

    1. 試著保存搜尋指標然後去找它,例如:
       $where = tell(LOG);
       seek(LOG, $where, 0);
      
    2. 如果那樣行不通,試著去seek() 檔案的另一部份然後再找回來。
    3. 如果還是行不通,試著seek() 檔案另一個相異的的部份,讀點東西,再回去找。
    4. 如果依然不行,放棄使用 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>; # 將所有從 stdin 來的丟到 socket
     } else {
     print while <$handle>; # 將所有 socket 來的丟到 stdout
     }
     close $handle;
     exit;
    

    如何在 Perl 里達到 Expect 的功能?

    很久很久以前,有個叫做 chat2.pl 的程式庫(perl 標準配備之一),但一直沒 真正完工?,F在,你的最佳選擇就是從CPAN 來的 Comm.pl 程式庫。


    有沒有可能將 perl 的指令列隱藏起來,以躲避像 "ps" 之類的程式?

    首先要注意的是,如果你的目的是為了安全(例如避免人們偷看到密碼),那你應 該重寫你的程式,把重要的資訊從參數中剔除。光是隱藏起來不會讓你的程式變得 完全安全。

    如要真的把看得見的指令列改掉,你可以設定$0 這個變數值,如同perlvar 里寫的。但這方法并非各種作業系統都適用。像 sendmail之類的背景程式 (daemons) 就將它們的狀態放在那兒:

     $0 = "orcus [aclearcase/" target="_blank" >ccepting connections]";
    

    我在 perl script 里 {更動目錄,更改我的使用環境}。為何這些改變在程式執行完後就消失了呢?如何讓我做的修改顯露出來?

    Unix
    嚴格的說起來,這是做不到的-一個 script 的執行是從啟動它的 shell 生出一 個不同的程序來執行。這個程序的任何變動不會反映到它的父程序,只會反映到更 改之後它自己創造出來的子程序。有個 shell 魔術可以讓你藉著在 shell 里eval()你 script 的輸出來裝出這種效果,在 comp.unix.questionsFAQ 里有詳 細內容。
    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_NDELAYO_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模組,遵循以下步 驟:

    1. 把原始碼解開放到一個暫存區域
    2.  perl Makefile.PL
      
    3.  make
      
    4.  make test
      
    5.  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..4) {
     my $got;
     print '給我: ';
     $got = getone();
     print "--> $got\n";
     }
     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() }
    


    原文轉自:http://www.kjueaiud.com

    ...
    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>