Manpages

NAME

perlfaq8 − 系 統 交 互 (2003/01/26 17:44:04 )

DESCRIPTION 描 述

Perl FAQ 的 這 一 節 覆 蓋 \[u4E86]與 系 統 交 互 有 關 的 問 題 。 主 題 包 括 進 程 間 通 信 (IPC), 使 用 者 界 面 控 制 (鍵 盤 , 螢 幕 和 指 點 設 備 ), 以 及 其 他 與 數 據 操 作 不 相 關 的 事 項

閱 \[u8B80]你 系 統 中 的 perl 自 帶 的 FAQ 和 文 件 (例 如 , perlvms,perlplan9...)。 它 們 會 包 含 有 關 你 的 perl 版 本 的 更 詳 細 的 信 息 。

如 何 找 出 正 在 運 行 的 作 業 系 統 ?

為 什 麼 exec() 不 返 回 ?

因 為 這 正 是 它 所 做 的 : 它 用 另 一 個 不 同 的 程 式 來 取 代 你 當 時 所 執 行 的 。 如 果 你 的 程 式 需 要 繼 續 跑 下 去 ( 這 可 能 正 是 你 問 此 問 題 的 原 因 吧 ? ) , 改 用 system() 。

如 何 對 鍵 盤 / 螢 幕 / 滑 鼠 做 些 花 樣 ?

連 接 / 控 制 鍵 盤 、 螢 幕 和 指 標 裝 置 ( 「 滑 鼠 」 ) 的 方 法 因 作 業 系 統 的 不 同 而 有 不 同 ; 不 妨 試 試 下 列 模 組 :
Keyboard

    Term::Cap                   標 準 內 建 模 組
    Term::ReadKey               CPAN
    Term::ReadLine::Gnu         CPAN
    Term::ReadLine::Perl        CPAN
    Term::Screen                CPAN

Screen

    Term::Cap                   標 準 內 建 模 組
    Curses                      CPAN
    Term::ANSIColor             CPAN

Mouse

    Tk                          CPAN

Some of these specific cases are shown below.

How do I print something out in color?

In general, you don’t, because you don’t know whether the recipient has a color-aware display device. If you know that they have an ANSI terminal that understands color, you can use the Term::ANSIColor module from CPAN:

    use Term::ANSIColor;
    print color("red"), "Stop!\n", color("reset");
    print color("green"), "Go!\n", color("reset");

Or like this:

    use Term::ANSIColor qw(:constants);
    print RED, "Stop!\n", RESET;
    print GREEN, "Go!\n", RESET;

How do I read just one key without waiting for a return key?

Controlling input buffering is a remarkably system-dependent matter. On many systems, you can just use the stty command as shown in "getc" in perlfunc, but as you see, that’s already getting you into portability snags.

    open(TTY, "+</dev/tty") or die "no tty: $!";
    system "stty  cbreak </dev/tty >/dev/tty 2>&1";
    $key = getc(TTY);           # perhaps this works
    # OR ELSE
    sysread(TTY, $key, 1);      # probably this does
    system "stty -cbreak </dev/tty >/dev/tty 2>&1";

The Term::ReadKey module from CPAN offers an easy-to-use interface that should be more efficient than shelling out to stty for each key. It even includes limited support for Windows.

    use Term::ReadKey;
    ReadMode(’cbreak’);
    $key = ReadKey(0);
    ReadMode(’normal’);

However, using the code requires that you have a working C compiler and can use it to build and install a CPAN module. Here’s a solution using the standard POSIX module, which is already on your systems (assuming your system supports POSIX ).

    use HotKey;
    $key = readkey();

And here’s the HotKey module, which hides the somewhat mystifying calls to manipulate the POSIX termios structures.

    # HotKey.pm
    package HotKey;
    @ISA = qw(Exporter);
    @EXPORT = qw(cbreak cooked readkey);
    use strict;
    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);  # ok, so i don’t want echo either
        $term->setcc(VTIME, 1);
        $term->setattr($fd_stdin, TCSANOW);
    }
    sub cooked {
        $term->setlflag($oterm);
        $term->setcc(VTIME, 0);
        $term->setattr($fd_stdin, TCSANOW);
    }
    sub readkey {
        my $key = ’’;
        cbreak();
        sysread(STDIN, $key, 1);
        cooked();
        return $key;
    }
    END { cooked() }
    1;

How do I check whether input is ready on the keyboard?

The easiest way to do this is to read a key in nonblocking mode with the Term::ReadKey module from CPAN , passing it an argument of −1 to indicate not to block:

    use Term::ReadKey;
    ReadMode(’cbreak’);
    if (defined ($char = ReadKey(-1)) ) {
        # input was waiting and it was $char
    } else {
        # no input was waiting
    }

    ReadMode(’normal’);                  # restore normal tty settings

How do I clear the screen?

If you only have do so infrequently, use "system":

    system("clear");

If you have to do this a lot, save the clear string so you can print it 100 times without calling a program 100 times:

    $clear_string = ’clear’;
    print $clear_string;

If you’re planning on doing other screen manipulations, like cursor positions, etc, you might wish to use Term::Cap module:

    use Term::Cap;
    $terminal = Term::Cap->Tgetent( {OSPEED => 9600} );
    $clear_string = $terminal->Tputs(’cl’);

How do I get the screen size?

If you have Term::ReadKey module installed from CPAN , you can use it to fetch the width and height in characters and in pixels:

    use Term::ReadKey;
    ($wchar, $hchar, $wpixels, $hpixels) = GetTerminalSize();

This is more portable than the raw "ioctl", but not as illustrative:

    require ’sys/ioctl.ph’;
    die "no TIOCGWINSZ " unless defined &TIOCGWINSZ;
    open(TTY, "+</dev/tty")                     or die "No tty: $!";
    unless (ioctl(TTY, &TIOCGWINSZ, $winsize=’’)) {
        die sprintf "$0: ioctl TIOCGWINSZ (%08x: $!)\n", &TIOCGWINSZ;
    }
    ($row, $col, $xpixel, $ypixel) = unpack(’S4’, $winsize);
    print "(row,col) = ($row,$col)";
    print "  (xpixel,ypixel) = ($xpixel,$ypixel)" if $xpixel ⎪⎪ $ypixel;
    print "\n";

如 何 向 使 用 者 詢 問 密 碼 ?

(這 個 問 題 跟 全 球 資 訊 網 一 點 關 系 也 沒 有 。 如 果 你 要 找 的 是 跟 WWW 有 關 的 , 那 就 看 另 一 份 常 見 問 題 集 吧 。 )

在 perlfunc 中 的 "crypt" 裏 面 有 個 範 例 。 首 先 , 將 你 的 終 端 機 設 為 「 無 回 應 」 "no echo" 模 式 , 然 後 就 用 平 常 的 方 法 將 密 碼 讀 入 。 你 可 以 用 老 式 的 ioctl() 函 數 、 POSIX 終 端 機 控 制 函 數 ( 參 看 POSIX , 和 駱 駝 書 第 七 章 ) , 或 是 呼 叫 stty 程 式 , 這 些 方 法 的 可 攜 性 / 移 植 性 程 度 都 不 一 樣 。

你 也 可 以 在 大 部 份 系 統 上 使 用 CPAN 裏 的 Term::ReadKey 模 組 , 這 個 模 組 較 易 使 用 而 且 理 論 上 也 較 據 可 攜 性 / 移 植 性 。

    use Term::ReadKey;

    ReadMode(’noecho’);
    $password = ReadLine(0);

如 何 讀 寫 串 口 ?

這 端 看 你 在 什 麼 作 業 系 統 上 執 行 你 的 程 式 。 以 Unix 來 說 , 序 列 埠 可 以 透 過 /dev 目 錄 下 的 檔 案 來 擷 取 ; 而 在 其 他 系 統 上 , 設 備 的 名 稱 無 疑 地 會 不 一 樣 。 以 下 是 一 些 在 設 備 互 動 時 可 能 遭 遇 的 共 同 問 題 :
lockfiles

你 的 系 統 可 能 會 使 用 鎖 檔 來 控 制 多 重 讀 寫 的 情 況 。 確 定 你 用 的 是 正 確 的 協 定 。 因 為 當 多 個 程 式 同 時 對 一 個 裝 置 做 讀 取 時 可 能 會 發 生 意 想 不 到 的 情 況 。

open mode

如 果 你 打 算 對 一 個 裝 置 同 時 做 讀 與 寫 的 動 作 , 你 得 將 它 開 到 更 新 的 模 式 ( 在 perlfunc 中 的 open 裏 有 更 詳 細 的 解 說 ) 。 如 果 你 不 希 望 冒 著 阻 擋 其 他 程 式 讀 取 這 個 裝 置 的 風 險 , 那 就 得 用 sysopen() 和 Fcntl 模 組 ( 標 準 perl 的 一 部 分 ) 內 的 "O_RDWR⎪O_NDELAY⎪O_NOCTTY"。 在 perlfunc 中 的 sysopen 裏 有 對 此 方 法 更 詳 盡 的 解 說 。

end of line

有 些 裝 置 會 等 著 在 每 行 結 尾 處 看 到 一 個 "\r", 而 非 "\n"。 在 某 些 平 台 上 的 perl, "\r"和 "\n" 與 它 們 平 常 ( 在 Unix 上 ) 所 指 的 ASCII 值 "\015" 和 "\012" 有 所 不 同 。 你 也 許 \[u5F97]直 接 給 定 數 值 , 例 如 用 八 進 位 ("\015")、 十 六 進 位 ("0x0D"), 或 指 定 控 制 字 元 ("\cM")。

    print DEV "atv1\012";       # wrong, for some devices
    print DEV "atv1\015";       # right, for some devices

儘 管 對 普 通 的 文 字 檔 案 , 一 個 "\n" 便 可 解 決 斷 行 的 問 題 , 但 目 前 在 不 同 作 業 系 統 間 ( Unix、 DOS/Win 和 Macintosh) , 對 於 斷 行 記 號 仍 無 統 一 標 準 , 而 只 有 用 "\015\012" 來 當 成 每 行 的 結 尾 , 然 後 再 視 需 要 去 掉 輸 出 中 不 想 要 的 部 份 。 這 個 做 法 尤 其 常 用 於 socket輸 出 / 輸 入 與 自 動 刷 新 (autoflushing), 也 是 接 下 來 要 討 論 的 主 題 。

flushing output

如 果 你 希 望 print() 的 時 候 每 個 字 元 都 要 送 到 你 指 定 的 裝 置 去 , 那 你 應 自 動 刷 新 檔 案 句 柄 。 可 以 使 用 select()$⎪ 變 量 控 制 自 動 刷 新 , 參 見 perlvar 中 的 "$⎪" 和 perlfunc 中 的 "select", 或 perlfaq5, ’’How do I flush/unbuffer an output filehandle? Why must I do this?’’):

    $oldh = select(DEV);
    $⎪ = 1;
    select($oldh);

你 也 可 能 看 到 不 使 用 額 外 的 暫 存 變 數 的 寫 法 , 例 如 :

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

Or if you don’t mind pulling in a few thousand lines of code just because you’re afraid of a little $⎪ variable:

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

As mentioned in the previous item, this still doesn’t work when using socket I/O between Unix and Macintosh. You’ll need to hard code your line terminators, in that case.

non-blocking input

如 果 你 正 在 做 一 個 阻 塞 的 read() 或 sysread() 動 作 , 則 你 需 要 安 排 一 個 鬧 鈴 把 手 或 提 供 一 個 逾 時 設 定 ( 參 看 alarm) 。 如 果 你 是 用 非 阻 擋 式 的 開 檔 , 那 麼 就 要 配 合 非 阻 擋 性 的 讀 取 , 也 就 是 說 得 用 到 4 個 參 數 的 select() 來 確 定 此 裝 置 的 輸 出 / 入 是 否 已 準 備 好 了 ( 參 考 perlfunc 中 的 select ) 。

While trying to read from his caller-id box, the notorious Jamie Zawinski <jwz [AT] netscape.com>, after much gnashing of teeth and fighting with sysread, sysopen, POSIX ’s tcgetattr business, and various other functions that go bump in the night, finally came up with this:

    sub open_modem {
        use IPC::Open2;
        my $stty = ’/bin/stty -g’;
        open2( \*MODEM_IN, \*MODEM_OUT, "cu -l$modem_device -s2400 2>&1");
        # starting cu hoses /dev/tty’s stty settings, even when it has
        # been opened on a pipe...
        system("/bin/stty $stty");
        $_ = <MODEM_IN>;
        chomp;
        if ( !m/^Connected/ ) {
            print STDERR "$0: cu printed ’$_’ instead of ’Connected’\n";
        }
    }

如 何 解 碼 加 密 的 口 令 檔 案 ?

花 大 把 大 把 的 錢 去 買 破 解 專 用 的 硬 體 , 這 會 讓 你 成 為 焦 點 話 題 。

說 正 經 的 , 如 果 是 碰 到 Unix 密 碼 檔 的 話 就 不 行 - Unix 密 碼 系 統 用 的 是 單 向 的 加 密 函 數 。 像 Crack 之 類 的 程 式 可 以 暴 力 地 ( 並 聰 明 地 ) 試 著 猜 出 密 碼 , 但 無 法 ( 也 不 能 ) 保 証 速 戰 速 決 。

如 果 你 耽 心 的 是 使 用 者 選 取 不 良 的 密 碼 , 你 應 該 在 使 用 者 換 密 碼 時 主 動 審 核 ( 例 如 說 修 改 passwd(1) 程 式 加 入 這 個 功 \[u80FD]) 。

如 何 在 背 景 開 啟 進 程 ?

Several modules can start other processes that do not block your Perl program. You can use IPC::Open3, Parallel::Jobs, IPC::Run, and some of the POE modules. See CPAN for more details.

你 可 以 使 用 :

    system("cmd &")

或 是 用 fork, 像 perlfunc 中 的 fork 裏 寫 的 ( 在 perlipc 裏 有 更 進 一 步 的 範 例 ) 。 如 果 你 在 Unix 類 的 系 統 上 的 話 , 請 注 意 以 下 幾 件 事 情 :
STDIN
, STDOUT , and STDERR are shared

主 程 式 和 背 景 程 式 ( 即 「 子 」 程 式 ) 共 用 同 一 個 STDIN、 STDOUT 和 STDERR 檔 案 把 手 。 如 果 兩 個 程 式 想 同 時 去 讀 、 寫 同 一 個 檔 案 把 手 , 就 可 能 有 怪 事 會 發 生 。 你 也 許 \[u61C9]該 替 子 程 式 關 閉 或 重 新 開 啟 這 些 把 手 。 你 可 以 用 開 啟 一 個 管 道 (pipe) 的 方 法 避 免 這 些 問 題 ( 參 看 open) 但 是 在 某 些 系 統 上 這 樣 做 會 強 迫 子 程 式 必 須 比 父 程 式 早 死 。

信 號

SIGCHLD、 可 能 還 有 SIGPIPE 這 兩 個 訊 號 要 抓 到 。 當 背 景 程 式 執 行 完 成 後 就 會 送 出 SIGCHLD 訊 號 。 而 當 你 寫 入 一 個 子 程 式 已 經 關 閉 的 檔 案 把 手 時 就 會 收 到 SIGPIPE 訊 號 ( 一 個 未 抓 住 的 SIGPIPE 可 能 導 致 你 的 程 式 無 聲 無 息 地 死 去 ) 。 用 system("cmd&") 的 話 不 會 有 這 樣 的 問 題 。

僵 屍 進 程

你 得 做 準 備 , 在 子 程 式 結 束 時 「 收 成 」 它 :

    $SIG{CHLD} = sub { wait };
    $SIG{CHLD} = ’IGNORE’;

You can also use a double fork. You immediately wait() for your first child, and the init daemon will wait() for your grandchild once it exits.

        unless ($pid = fork) {
                unless (fork) {
            exec "what you really wanna do";
            die "exec failed!";
                }
        exit 0;
        }
    waitpid($pid,0);

在 Signals 有 範 例 程 式 教 你 怎 麼 做 。 用 system("prog &") 的 話 不 會 有 僵 程 式 的 問 題 。

如 何 截 獲 控 制 字 符 /信 號 ?

你 並 不 能 真 的 ’’捕 捉 ’’ 一 個 控 制 字 元 。 而 是 控 制 字 元 產 生 一 個 訊 號 讓 你 捕 捉 。 關 於 訊 號 的 資 料 可 以 在 Signals 以 及 駱 駝 書 第 六 章 裏 找 到 。

要 小 心 的 是 , 大 多 C 程 式 庫 無 法 重 新 進 入 [re-entrant]。 因 此 當 你 要 嘗 試 著 在 一 個 處 理 器 裏 做 print() 動 作 , 而 這 個 處 理 器 是 由 另 一 個 stdio 的 動 作 所 叫 出 來 的 話 , 你 的 內 部 結 構 可 能 會 處 於 失 調 狀 態 , 而 程 式 可 能 會 丟 出 記 憶 核 心 (dump core)。 有 的 時 候 你 可 以 用 syswrite() 取 代 print() 以 避 免 這 個 狀 況 。

除 非 你 極 為 小 心 , 否 則 在 一 個 訊 號 處 理 器 中 , 唯 一 安 全 可 做 的 是 : 設 定 一 個 變 數 後 離 開 。 而 在 第 一 個 情 況 下 , 你 在 設 定 變 數 的 時 候 應 確 定 malloc() 不 會 被 叫 出 來 ( 譬 如 , 設 定 一 個 已 經 有 值 的 變 數 ) 。

例 如 :

    $Interrupted = 0;   # 確 定 它 有 個 值
    $SIG{INT} = sub {
        $Interrupted++;
        syswrite(STDERR, "ouch\n", 5);
    }

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

在 Unix 系 統 中 如 何 修 改 shadow 檔 案 ?

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

如 何 設 置 時 間 和 日 期 ?

假 設 你 有 足 夠 的 權 限 , 你 應 該 可 以 用 date(1) 程 式 來 設 定 系 統 的 時 間 與 日 期 。 ( 但 沒 有 針 對 個 別 程 式 修 改 時 間 日 期 的 方 法 ) 這 機 制 在 Unix、 MS-DOS、 Windows 和 NT 下 都 能 用 ; VMS 下 則 要 用 set time 。

然 而 , 如 果 你 只 是 要 更 動 你 的 時 區 , 只 消 設 定 一 個 環 境 變 數 即 可 :

    $ENV{TZ} = "MST7MDT";                  # unixish
    $ENV{’SYS$TIMEZONE_DIFFERENTIAL’}="-5" # vms
    system "trn comp.lang.perl.misc";

如 何 sleep() 或 alarm() 少 於 一 秒 的 時 間 ?

如 果 你 要 比 sleep() 所 提 供 的 最 小 單 位 一 秒 更 精 細 的 話 , 最 簡 單 的 方 法 就 是 用 select 裏 面 寫 的 select() 函 數 。 試 一 試 Time::HiRes 和 BSD::Itimer 模 塊 (可 以 從 CPAN 下 載 , 從 Perl 5.8 開 始 Time::HiRes 成 為 標 準 發 行 的 一 部 分 ).

如 何 測 度 少 於 一 秒 的 時 間 ?

一 般 來 說 , 你 可 能 做 不 到 。 Time::HiRes 模 組 ( CPAN 有 , 從 Perl 5.8 開 始 成 為 標 準 發 行 的 一 部 分 ) 在 某 些 系 統 上 能 達 到 此 功 \[u80FD]。

總 之 , 你 可 能 做 不 到 。 但 是 如 果 你 的 Perl 支 援 syscall() 函 數 並 支 援 類 似 gettimeofday(2) 的 系 統 呼 叫 , 你 也 許 \[u53EF]以 這 麼 做 :

    require ’sys/syscall.ph’;
    $TIMEVAL_T = "LL";
    $done = $start = pack($TIMEVAL_T, ());
    syscall(&SYS_gettimeofday, $start, 0) != -1
               or die "gettimeofday: $!";
       ##########################
       # DO YOUR OPERATION HERE #
       ##########################
    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 檔 案 ) 。

For example, you can use this to make sure your filter program managed to finish its output without filling up the disk:

    END {
        close(STDOUT) ⎪⎪ die "stdout close failed: $!";
    }

如 果 當 程 式 被 沒 有 抓 到 的 訊 號 終 結 了 , 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 裏 的 模 組 , 因 為 也 許 \[u67D0]人 已 經 寫 了 個 這 樣 的 模 組 。 On Windows, try Win32::API. On Macs, try Mac::Carbon. If no module has an interface to the C function, you can inline a bit of C in your Perl source with Inline::C.

在 哪 裏 可 以 找 引 入 檔 來 做 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() 來 完 成 此 工 作 。 不 過 切 記 要 讀 它 檔 案 裏 關 於 鎖 死 的 警 告 ( 參 見 IPC::Open2 )。 參 見 perlipc 中 的 "Bidirectional Communication with Another Process" 和 "Bidirectional Communication with Yourself"

You may also use the IPC::Open3 module (part of the standard perl distribution), but be warned that it has a different order of arguments from IPC::Open2 (see IPC::Open3).

為 何 用 system()卻 得 不 到 一 個 指 令 的 輸 出 呢 ?

你 把 system() 和 反 向 引 號 (’’) 的 用 法 搞 混 了 。 system() 會 執 行 一 個 指 令 然 後 傳 回 指 令 結 束 時 的 狀 況 資 訊 ( 以 一 個 16 進 位 值 表 示 : 低 位 元 是 程 式 中 止 所 收 到 的 訊 號 , 高 位 元 才 是 真 正 離 開 時 的 傳 回 值 ) 。 反 向 引 號 (’’) 執 行 一 個 指 令 並 且 把 它 所 送 出 的 東 西 送 到 STDOUT。

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

如 何 捕 捉 外 部 指 令 的 STDERR?

有 三 種 基 本 方 式 執 行 外 部 指 令 :

    system $cmd;                # 使 用  system()
    $output = ’$cmd’;           # 使 用  backticks (’’)
    open (PIPE, "cmd ⎪");       # 使 用  open()

在 system() 下 , STDOUT 和 STDERR 都 會 輸 出 到 和 script 本 身 的 STDOUT, STDERR相 同 的 出 處 , 除 非 指 令 本 身 將 它 們 導 向 它 處 。 反 向 引 號 和 open() 則 只 讀 取 指 令 的 STDOUT 部 份 。

你 也 可 以 使 用 IPC::Open3 模 組 . Benjamin Goldberg provides some sample code:

To capture a program’s STDOUT , but discard its STDERR:

    use IPC::Open3;
    use File::Spec;
    use Symbol qw(gensym);
    open(NULL, ">", File::Spec->devnull);
    my $pid = open3(gensym, \*PH, ">&NULL", "cmd");
    while( <PH> ) { }
    waitpid($pid, 0);

To capture a program’s STDERR , but discard its STDOUT:

    use IPC::Open3;
    use File::Spec;
    use Symbol qw(gensym);
    open(NULL, ">", File::Spec->devnull);
    my $pid = open3(gensym, ">&NULL", \*PH, "cmd");
    while( <PH> ) { }
    waitpid($pid, 0);

To capture a program’s STDERR , and let its STDOUT go to our own STDERR:

    use IPC::Open3;
    use Symbol qw(gensym);
    my $pid = open3(gensym, ">&STDERR", \*PH, "cmd");
    while( <PH> ) { }
    waitpid($pid, 0);

To read both a command’s STDOUT and its STDERR separately, you can redirect them to temp files, let the command run, then read the temp files:

    use IPC::Open3;
    use Symbol qw(gensym);
    use IO::File;
    local *CATCHOUT = IO::File->new_tempfile;
    local *CATCHERR = IO::File->new_tempfile;
    my $pid = open3(gensym, ">&CATCHOUT", ">&CATCHERR", "cmd");
    waitpid($pid, 0);
    seek $_, 0, 0 for \*CATCHOUT, \*CATCHERR;
    while( <CATCHOUT> ) {}
    while( <CATCHERR> ) {}

But there’s no real need for *both* to be tempfiles... the following should work just as well, without deadlocking:

    use IPC::Open3;
    use Symbol qw(gensym);
    use IO::File;
    local *CATCHERR = IO::File->new_tempfile;
    my $pid = open3(gensym, \*CATCHOUT, ">&CATCHERR", "cmd");
    while( <CATCHOUT> ) {}
    waitpid($pid, 0);
    seek CATCHERR, 0, 0;
    while( <CATCHERR> ) {}

And it’ll be faster, too, since we can begin processing the program’s stdout immediately, rather than waiting for the program to finish.

在 上 述 方 法 中 , 你 可 以 在 呼 叫 前 更 改 檔 案 描 述 符 (file descriptor) 名 稱 :

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

或 者 使 用 Bourne shell 的 檔 案 描 述 符 重 導 功 \[u80FD]:

    $output = ’$cmd 2>some_file’;
    open (PIPE, "cmd 2>some_file ⎪");

也 可 以 用 檔 案 描 述 元 重 導 功 \[u80FD]將 STDERR 複 製 為 STDOUT:

    $output = ’$cmd 2>&1’;
    open (PIPE, "cmd 2>&1 ⎪");

注 意 你 不 能 光 是 將 STDERR 開 成 STDOUT 的 複 製 , 而 不 呼 叫 shell來 做 這 個 重 導 的 工 作 。 這 樣 是 不 行 的 :

    open(STDERR, ">&STDOUT");
    $alloutput = ’cmd args’;  # stderr still escapes

失 敗 的 原 因 是 , open() 讓 STDERR 在 呼 叫 open() 時 往 STDOUT的 方 向 走 。 然 後 反 向 引 號 讓 STDOUT的 內 容 跑 到 一 個 字 串 變 數 裏 , 但 是 沒 有 改 變 STDERR 的 去 向 ( 它 仍 然 往 舊 的 STDOUT那 裏 跑 ) 。

注 意 , 在 反 向 引 號 裏 你 必 須 使 用 Bourne shell (sh(1)) 重 導 的 語 法 而 非 csh(1)的 ! 至 於 為 何 Perl 的 system()、 反 向 引 號 和 開 管 道 都 用 Bourne shell語 法 的 原 因 , 可 在 下 址 找 到 : "Far More Than You Ever Wanted To Know", http://www.cpan.org/misc/olddoc/FMTEYEWTK.tgz . 要 同 時 捕 捉 一 個 命 令 的 STDERRSTDOUT :

    $output = ’cmd 2>&1’;                       # either with backticks
    $pid = open(PH, "cmd 2>&1 ⎪");              # or with an open pipe
    while (<PH>) { }                            #    plus a read

To capture a command’s STDOUT but discard its STDERR:

    $output = ’cmd 2>/dev/null’;                # either with backticks
    $pid = open(PH, "cmd 2>/dev/null ⎪");       # or with an open pipe
    while (<PH>) { }                            #    plus a read

To capture a command’s STDERR but discard its STDOUT:

    $output = ’cmd 2>&1 1>/dev/null’;           # either with backticks
    $pid = open(PH, "cmd 2>&1 1>/dev/null ⎪");  # or with an open pipe
    while (<PH>) { }                            #    plus a read

To exchange a command’s STDOUT and STDERR in order to capture the STDERR but leave its STDOUT to come out our old STDERR:

    $output = ’cmd 3>&1 1>&2 2>&3 3>&-’;        # either with backticks
    $pid = open(PH, "cmd 3>&1 1>&2 2>&3 3>&-⎪");# or with an open pipe
    while (<PH>) { }                            #    plus a read

To read both a command’s STDOUT and its STDERR separately, it’s easiest and safest to redirect them separately to files, and then read from those files when the program is done:

    system("program args 1>/tmp/program.stdout 2>/tmp/program.stderr");

Ordering is important in all these examples. That’s because the shell processes file descriptor redirections in strictly left to right order.

    system("prog args 1>tmpfile 2>&1");
    system("prog args 2>&1 1>tmpfile");

The first command sends both standard out and standard error to the temporary file. The second command sends only the old standard output there, and the old standard error shows up on the old standard out.

為 何 當 管 道 開 啟 失 敗 時 open()不 會 傳 回 錯 誤 訊 息 ?

If the second argument to a piped open() contains shell metacharacters, perl fork()s, then exec()s a shell to decode the metacharacters and eventually run the desired program. If the program couldn’t be run, it’s the shell that gets the message, not Perl. All your Perl program can find out is whether the shell itself could be successfully started. You can still capture the shell’s STDERR and check it for error messages. See "How can I capture STDERR from an external command?" elsewhere in this document, or use the IPC::Open3 module.

If there are no shell metacharacters in the argument of open(), Perl runs the command directly, without using the shell, and can correctly report whether the command started.

在 忽 略 返 回 值 的 上 下 文 裏 使 用 反 向 引 號 有 何 不 對 ?

嚴 格 說 起 來 , 沒 啥 不 對 。 但 從 程 式 寫 作 嚴 謹 與 否 來 說 , 這 樣 無 法 寫 出 較 易 維 護 的 程 式 碼 。 Perl 有 多 種 方 法 可 以 運 行 外 部 命 令 。 反 引 號 只 是 其 中 一 個 ; 它 收 集 命 令 的 輸 出 , 在 程 式 中 加 以 應 用 。 "system" 函 數 是 另 一 個 , 它 不 這 樣 做

Writing backticks in your program sends a clear message to the readers of your code that you wanted to collect the output of the command. Why send a clear message that isn’t true?

再 看 看 下 列 這 一 行 :

    ’cat /etc/termcap’;

你 還 沒 有 指 定 輸 出 , 所 以 它 會 浪 費 記 憶 體 ( 就 那 麼 一 下 子 )。 另 外 你 也 忘 了 檢 查 $? 看 看 程 式 是 否 正 確 的 執 行 。 即 使 你 寫 成

    print ’cat /etc/termcap’;

但 在 大 部 份 情 況 下 , 這 本 來 可 以 、 而 且 也 應 該 寫 成

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

這 樣 可 快 速 地 得 到 輸 出 ( 一 產 生 出 來 就 會 得 到 , 不 用 等 到 最 後 ) , 並 且 檢 查 傳 回 值 。

system() 同 時 具 有 直 接 決 定 是 否 先 做 shell 萬 用 字 元 (wildcard)處 理 的 功 \[u80FD], 反 向 引 號 就 不 行 。

如 何 不 經 過 shell處 理 來 呼 叫 反 向 引 號 ?

這 需 要 些 技 巧 。 不 能 寫 成 這 樣 :

    @ok = ’grep @opts ’$search_string’ @filenames’;

在 Perl 5.8.0 中 , 你 可 以 使 用 有 多 個 參 數 的 open()。 類 似 system()exec() 的 列 表 形 式 , 不 會 進 行 shell 轉 義 。

   open( GREP, "-⎪", ’grep’, @opts, $search_string, @filenames );
   chomp(@ok = <GREP>);
   close GREP;

也 可 以 這 樣 :

    my @ok = ();
    if (open(GREP, "-⎪")) {
        while (<GREP>) {
            chomp;
            push(@ok, $_);
        }
        close GREP;
    } else {
        exec ’grep’, @opts, $search_string, @filenames;
    }

一 如 system(), 當 你 exec() 一 個 序 列 時 不 會 有 shell 解 譯 的 情 況 發 生 。 更 多 示 例 可 以 從 perlipc 的 "Safe Pipe Opens" 中 找 到 。

Note that if you’re use Microsoft, no solution to this vexing issue is even possible. Even if Perl were to emulate fork(), you’d still be stuck, because Microsoft does not have a argc/argv−style API .

為 何 給 了 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;             # new in 5.004
    $handle = IO::Socket::INET->new(’www.perl.com:80’)
            ⎪⎪ die "can’t connect to port 80 on www.perl.com: $!";
    $handle->autoflush(1);
    if (fork()) {               # XXX: undef means failure
        select($handle);
        print while <STDIN>;    # everything from stdin to socket
    } else {
        print while <$handle>;  # everything from socket to stdout
    }
    close $handle;
    exit;

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

很 久 很 久 以 前 , 有 個 叫 做 chat2.pl 的 程 式 庫 ( perl 標 準 配 備 之 一 ) , 但 一 直 沒 真 正 完 工 。 如 果 遇 到 它 的 話 , 不 要 去 用 它 。 現 在 , 你 的 最 佳 選 擇 就 是 從 CPAN 來 的 Expect 模 塊 , 同 時 它 需 要 CPAN 的 另 兩 個 模 塊 , IO::Pty 和 IO::Stty.

有 沒 有 可 能 將 perl的 指 令 列 隱 藏 起 來 , 以 躲 避 像

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

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

    $0 = "orcus [accepting connections]";

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

嚴 格 的 說 起 來 , 這 是 做 不 到 的 - 一 個 script 的 執 行 是 從 啟 動 它 的 shell 生 出 一 個 不 同 的 程 式 來 執 行 。 這 個 程 式 的 任 何 變 動 不 會 反 映 到 它 的 父 程 式 , 只 會 反 映 到 更 改 之 後 它 自 己 創 造 出 來 的 子 程 式 。 有 個 shell 魔 術 可 以 讓 你 藉 著 在 shell 裏 eval()你 script 的 輸 出 來 裝 出 這 種 效 果 , 在 comp.unix.questions FAQ 裏 有 詳 細 內 容 。

如 何 關 閉 一 個 程 式 的 檔 案 句 柄 而 不 用 等 它 完 成 呢 ?

假 設 你 的 系 統 支 援 這 種 功 \[u80FD], 那 就 只 要 送 個 適 當 的 訊 號 給 此 程 式 ( 參 看 kill) 。 通 常 是 先 送 一 個 TERM 訊 號 , 等 一 下 下 , 然 後 再 送 個 KILL 訊 號 去 終 結 它 。

如 何 fork 一 個 守 護 進 程 ?

如 果 你 所 指 的 是 離 線 的 程 式 ( 未 與 tty 連 線 者 ) , 那 下 列 的 程 式 據 說 在 大 部 份 的 Unix系 統 都 能 用 。 非 Unix 系 統 的 使 用 者 應 該 檢 查 Your_OS::Process 模 組 看 看 有 沒 有 其 他 的 解 決 方 案 。

打 開 /dev/tty 然 後 對 它 用 TIOCNOTTY ioctl。 請 參 考 tty(4) 。 更 好 的 辦 法 , 你 可 以 只 用 POSIX::setsid() 函 數 , 從 而 不 必 擔 心 進 程 組 。

把 目 錄 換 到 /

重 開 STDIN、 STDOUT 和 STDERR 使 它 們 不 會 與 舊 的 tty 連 接 。

用 下 列 方 法 把 程 式 丟 到 背 景 :

    fork && exit;

The Proc::Daemon module, available from CPAN , provides a function to perform these actions for you.

如 何 知 道 自 己 是 否 在 交 互 地 運 行 ?

問 得 好 。 有 的 時 候 "−t STDIN"N 和 "−t STDOUT" 可 以 提 供 線 索 , 有 時 不 行 。

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

在 POSIX 系 統 中 , 你 可 以 用 以 下 方 法 測 試 你 自 己 的 程 式 群 組 與 現 在 控 制 你 終 端 機 的 是 否 相 同 :

    use POSIX qw/getpgrp tcgetpgrp/;
    open(TTY, "/dev/tty") or die $!;
    $tpgrp = tcgetpgrp(fileno(*TTY));
    $pgrp = getpgrp();
    if ($tpgrp == $pgrp) {
        print "foreground\n";
    } else {
        print "background\n";
    }

如 何 為 緩 慢 的 事 件 設 置 超 時 ?

如 同 Signals 和 Camel 書 第 六 章 裏 所 描 述 的 , 用 alarm() 函 數 , 或 許 \[u518D]配 合 上 一 個 訊 號 處 理 器 。 你 也 可 以 改 用 CPAN 裏 更 具 彈 性 的 Sys::AlarmCall 模 組 來 做 。

The alarm() function is not implemented on all versions of Windows. Check the documentation for your specific version of Perl.

如 何 設 置 CPU 限 額 ?

使 用 CPAN 裏 的 BSD::Resource 模 組 。

如 何 避 免 在 Unix 系 統 中 產 生 僵 屍 進 程 ?

使 用 Signals 裏 面 叫 reaper 的 程 式 碼 , 在 接 到 SIGCHLD 時 會 呼 叫 wait(), 或 是 用 perlfaq8 中 的 "How do I start a process in the background?" 裏 面 寫 的 雙 fork 技 巧 。

如 何 使 用 SQL 數 據 庫 ?

The DBI module provides an abstract interface to most database servers and types, including Oracle, DB2 , Sybase, mysql, Postgresql, ODBC , and flat files. The DBI module accesses each database type through a database driver, or DBD . You can see a complete list of available drivers on CPAN: http://www.cpan.org/modules/by−module/DBD/ . You can read more about DBI on http://dbi.perl.org .

Other modules provide more specific access: Win32::ODBC, Alzabo, iodbc, and others found on CPAN Search: http://search.cpan.org .

如 何 使 system() 在 收 到 control-C 時 退 出 ?

做 不 到 。 你 需 要 摹 仿 system() 呼 叫 ( 參 看 perlipc 裏 的 範 例 程 式 ) , 然 後 設 計 一 個 訊 號 處 理 器 , 讓 它 把 INT 訊 號 傳 給 子 程 式 。 或 者 可 以 檢 測 它 :

    $rc = system($cmd);
    if ($rc & 127) { die "signal death" }

如 何 無 阻 塞 地 打 開 一 個 檔 案 ?

如 果 你 有 幸 使 用 到 支 援 無 阻 塞 讀 的 系 統 ( 大 部 份 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: $!":

How do I install a module from CPAN ?

最 簡 單 的 方 法 就 是 讓 CPAN 這 個 模 組 替 你 代 勞 。 這 個 模 組 包 含 在 5.004及 以 後 的 版 本 中 。

    $ perl -MCPAN -e shell
    cpan shell -- CPAN exploration and modules installation (v1.59_54)
    ReadLine support enabled
    cpan> install Some::Module

如 要 手 動 安 裝 CPAN 模 組 , 或 是 任 何 按 規 矩 發 展 的 CPAN模 組 , 遵 循 以 下 步 驟 :

1

把 原 始 碼 解 壓 到 臨 時 目 錄

2

    perl Makefile.PL

3

    make

4

    make test

5

    make install

如 果 你 用 的 perl 版 本 在 編 譯 時 沒 有 建 入 動 態 連 結 的 功 \[u80FD], 那 你 只 消 把 第 三 步 (make)換 成 make perl 然 後 你 就 會 得 到 一 個 新 的 perl 執 行 檔 , 裏 頭 連 有 你 新 加 入 的 延 伸 。

在 ExtUtils::MakeMaker 裏 面 有 更 多 關 於 建 構 模 組 的 細 節 , 並 參 考 下 一 個 問 題 , require 和 use 的 區 別 是 什 麼 ? 。

require 和 use 的 區 別 是 什 麼 ?

Perl offers several different ways to include code from one file into another. Here are the deltas between the various inclusion constructs:

    1)  do $file is like eval ’cat $file’, except the former
        1.1: searches @INC and updates %INC.
        1.2: bequeaths an *unrelated* lexical scope on the eval’ed code.
    2)  require $file is like do $file, except the former
        2.1: checks for redundant loading, skipping already loaded files.
        2.2: raises an exception on failure to find, compile, or execute $file.
    3)  require Module is like require "Module.pm", except the former
        3.1: translates each "::" into your system’s directory separator.
        3.2: primes the parser to disambiguate class Module as an indirect object.

    4)  use Module is like require Module, except the former
        4.1: loads the module at compile time, not run-time.
        4.2: imports symbols and semantics from that package to the current one.

In general, you usually want "use" and a proper Perl module.

如 何 設 置 我 自 己 的 模 塊 /庫 路 徑 ?

當 你 建 構 模 組 時 , 在 產 生 Makefiles 時 使 用 PREFIX 選 項 :

    perl Makefile.PL PREFIX=/mydir/perl LIB=/mydir/perl/lib

然 後 在 執 行 用 到 此 模 組 / 程 式 庫 的 程 式 前 先 設 好 PERL5LIB 環 境 變 數 ( 參 考 perlrun ) , 或 是 用

    use lib ’/mydir/perl/lib’;

這 樣 與 下 面 幾 乎 相 同

    BEGIN {
        unshift(@INC, ’/mydir/perl/lib’);
    }

但 lib 模 塊 檢 測 獨 立 於 機 器 的 子 目 錄 。 參 見 Perl 的 lib 模 塊 來 獲 取 詳 細 信 息 。

如 何 將 我 自 己 的 程 式 的 路 徑 加 入 到 模 塊 /庫 搜 索 路 徑 中 ?

    use FindBin;
    use lib "$FindBin::Bin";
    use your_own_modules;

如 何 在 運 行 時 將 一 個 目 錄 加 入 到 我 的 include 路 徑 (@INC) 中 ?

以 下 是 我 們 建 議 更 動 引 入 路 徑 的 方 法 :

    環 境 變 量  PERLLIB
    環 境 變 量  PERL5LIB
    perl -Idir 命 令 行 標 誌
    use lib 編 用 , 類 似
        use lib "$ENV{HOME}/myown_perllib";

後 者 特 別 有 用 , 因 為 它 知 道 與 機 器 相 關 的 架 構 。 lib.pm 機 制 模 組 是 從 5.002 版 開 始 包 含 在 Perl 裏 面 的 。

什 麼 是 socket.ph, 從 哪 兒 可 以 得 到 它 ?

It’s a perl4−style file defining values for system networking constants. Sometimes it is built using h2ph when Perl is installed, but other times it is not. Modern programs "use Socket;" instead.

AUTHOR AND COPYRIGHT

Copyright (c) 1997−2003 Tom Christiansen and Nathan Torkington. All rights reserved.

This documentation is free; you can redistribute it and/or modify it under the same terms as Perl itself.

Irrespective of its distribution, all code examples in this file are hereby placed into the public domain. You are permitted and encouraged to use this code in your own programs for fun or for profit as you see fit. A simple comment in the code giving credit would be courteous but is not required.

譯 者

陳 彥 銘 , 蕭 百 齡 , 兩 只 老 虎 工 作 室