网站建设| 数据库类| 图形图象| 程序设计| 现代办公| 操作系统| 考试认证| 网络技术| 软件工程| 电脑相关| 文学作品
网站开发| 网页制作| 操作系统| 图象图形| 考试认证| 数据库类| 程序设计| 硬件技术| 现代办公| 网络技术| 笑话频道
 
您的位置: 电脑书库首页-> 电脑文摘-> 操作系统-> Unix系列-> UNIX常见问题解答(三)

UNIX常见问题解答(三)
作者:佚名 来源:InterNet 加入时间:2004-11-10
相关文章
  • Tru64 unix--Trucluster 安装手册
  • Tru64 UNIX系统磁盘备份与恢复
  • UNIX系统远程存取操作
  • SCO UnixWare 7下磁带机的安装与备份
  • SCO UNIX的注册警告信息
  • SCO UNIX操作系统序列号冲突
  • UNIX下format和tar易用性的一种改进方法
  • UnixWare 7 root口令遗失的解决方法
  • 在SCO UNIX系统中使用光驱
  • UNIX系统安全
  • 相关书籍:
  • tcpip详解卷三:tcp事务协议,http,nntp和unix域协议
  • Unix傻瓜书
  • SCO UNIX入门
  • 莱昂氏UNIX源代码分析
  • Unix操作手册英文版 
  • UNIX系统安全工具
  • SCO UNIX实用教程
  • 本篇文章回答以下问题;

    3.1)?nbsp;要如何得知一个档案建立的时间?
    3.2) 在执行 rsh 的时候要怎样才能不必等远方指令执行结束就回到 shell?
    3.3) 要怎样才能截断一个档案?
    3.4) 为什么执行 find 时所使用的 {} 符号无法达到我预期的结果?
    3.5) 我要如何改变一个 symbolic link 的 permission 呢?
    3.6) 我要如何 "undelete" 一个档案?
    3.7) 一个process 要怎样侦测出自己是否在背景状态执行?
    3.8) 为什么在 Bourne shell 当中,对回圈的输出入转向无法达到预期的效果?
    3.9) 我要怎么在一个 shell script 中或在背景执行 'ftp'、'telnet'、'tip' 等
    interactive 的程式呢?
    3.10) 在 shell script 或 C 程式当中,要怎样才能找到某个程式的 process ID
    呢?
    3.11) 我要怎样经由 rsh 执行远方指令时,检查远方指令的结束状态?
    3.12) 能不能把 shell 变数传进 awk 程式当中呢?
    3.13) 要怎样才能避免在记忆体中留下zombie processes?
    3.14) 当我要从 pipe 读一行输入时,要如何才能让这行资料像是直接从键盘输
    入而非从一个大 block buffer 来的?
    3.15) 我要如何在档案名字中加入日期?
    3.16) 为什么有一?nbsp;script 是用 #! ... 做为档案的开端?

    3.1) 我要如何得知一个档案建立的时间?

    很遗憾,因为档案建立的时间并未储存在任何地方,所以答案是无法得知。
    关于一个档案你只能查到最后修改的时间("ls -l"),最后读取的时间
    ("ls -lu") 与 inode 改变的使间。有一些 man pages 将最后一个时间当
    成是建立的时间,这种说法是错的。因为 mv、ln、chmod、chmod、chown、
    chgrp 等动作都会改变这个时间。

    若需更详尽的说明可参考 "stat(2)" 的 man page.


    3.2) 在执行 rsh 的时候要怎样才能不必等远方指令执行结束就回到 shell?
    (关于我们所讨论的 rsh,请参阅问题2.7)

    以下这些凭直觉想到的答案都达不到这个效果:
    rsh machine command &

    rsh machine 'command &'

    例如, 执行 rsh machine 'sleep 60 &' 这个命令时,我们可以观察到:rsh并
    不会立刻结束,而是等到远方的 sleep 命令完成以后才结束,即使我们在远
    方使用背景方式执行此命令。所以要怎样才能让 rsh 在 sleep命令启动后立
    刻结束呢?

    答案如下-

    如果您在远端使用csh:
    rsh machine -n 'command >&/dev/null </dev/null &'

    如果您在远端使用 sh:
    rsh machine -n 'command >/dev/null 2>&1 </dev/null &'

    为什么呢?因为 "-n" 会把 rsh 的stdin接到 /dev/null,因此您可以在本地
    机器以背景方式执行整个 rsh 命令。不管是使用 -n 选项或者在指令结尾使
    用 "/dev/null",其效果都是一样的。此外,在远端机器使用的输出入转向(写
    在单引号内的部份)会让 rsh 认定此次连线可迳行结束(因为已无其他输
    入资料)。

    附注: 任何档案都可以用于远端机器的输出入转向,而不仅限于 /dev/null。

    在许多状况下,这个复杂的命令当中有很多部份都是非必要的。


    3.3) 要怎样才能截断一个档案?

    BSD 的函数ftruncate() 可以设定档案的长度。但是并不是每一种版本的动作
    都一样。其他 UNIX 的变种似乎也都支援其他版本的截断功能。

    支援 ftruncate函数的系统多半可归类为以下三种:

    BSD 4.2 - Ultrix, SGI, LynxOS
    -无法使用截断功能来增加档案长度
    -执行截断动作不会移动档案指标

    BSD 4.3 - SunOS, Solaris, OSF/1, HP/UX, Amiga
    -可以用截断功能来增加档案长度
    -执行截断动作不会移动档案指标

    Cray - UniCOS 7, UniCOS 8
    -无法使用截断功能来增加档案长度
    -执行截断动作会移动档案指标

    其他系统则可能在以下四个地方与众不同:

    F_CHSIZE - 只在SCO 上
    -有些系统定义了F_CHSIZE 但并没有真的支援此功能
    -动作类似BSD 4.3

    F_FREESP - 只在 Interative Unix 上
    -有些系统(如Interactive Unix)定义了F_FREESP 但并没有真的支援此
    功能
    -动作类似BSD 4.3

    chsize() - QNX and SCO
    -有些系统(如Interactive Unix)有chsize() 函数但并没有真的支援
    此功能
    -动作类似BSD 4.3

    「空空如也」-目前找不到这种系统
    -也许会有系统完全不支援 truncate功能

    FAQ 维护者的注解:以下是我在几年前从网路抓到的程式,原作者已不可考,
    不过S.Spencer Sun <spencer@ncd.com> 也贡献了一份
    F_FREESP的功能。

    functions for each non-native ftruncate follow

    /* ftruncate emulations that work on some System V's.
    This file is in the public domain. */

    #include
    #include

    #ifdef F_CHSIZE
    int
    ftruncate (fd, length)
    int fd;
    off_t length;
    {
    return fcntl (fd, F_CHSIZE, length);
    }
    #else
    #ifdef F_FREESP
    /* The following function was written by
    kucharsk@Solbourne.com (William Kucharski) */

    #include
    #include
    #include

    int
    ftruncate (fd, length)
    int fd;
    off_t length;
    {
    struct flock fl;
    struct stat filebuf;

    if (fstat (fd, &filebuf) < 0)
    return -1;

    if (filebuf.st_size < length)
    {
    /* Extend file length. */
    if (lseek (fd, (length - 1), SEEK_SET) < 0)
    return -1;

    /* Write a "0" byte. */
    if (write (fd, "", 1) != 1)
    return -1;
    }
    else
    {
    /* Truncate length. */
    fl.l_whence = 0;
    fl.l_len = 0;
    fl.l_start = length;
    fl.l_type = F_WRLCK; /* Write lock on file space. */

    /* This relies on the UNDOCUMENTED F_FREESP argument to
    fcntl, which truncates the file so that it ends at the
    position indicated by fl.l_start.
    Will minor miracles never cease? */
    if (fcntl (fd, F_FREESP, &fl) < 0)
    return -1;
    }

    return 0;
    }
    #else
    int
    ftruncate (fd, length)
    int fd;
    off_t length;
    {
    return chsize (fd, length);
    }
    #endif
    #endif


    3.4) 为什么执行 find 时所使用的 {} 符号无法达到我预期的结果?

    Find 指令有一个 -exec 的选项会针对每一个找到的档案执行一个特殊
    的指令。Find 会把出现{}的地方置换成目前找到的档案名称。因此,
    也许有一天您会使用 find 指令对每一个档案执行某个指令,或者对
    一个目录执行某个指令。

    find /path -type d -exec command {}/\* \;

    希望 find 能依序执行以下指令:

    command directory1/*
    command directory2/*
    ...

    不幸的是,find 只会展开自成一体的 {} token;如果 {} 跟其他字元相连
    的话(如:{}/*),那么find将不会以您所想的方式展开 {}, 而是转换为以
    下命令

    command {}/*
    command {}/*
    ...

    也许您可以把它当成 bug, 也可以把它看成是故意设计的特异功能。但我们
    可不愿被目前这个特异功能干扰。所以要怎样避免这个问题呢?其中一种做
    法是写一个小小的 shell script,名称就叫做 ./doit 好了,其内容如下:

    command "$1"/*

    那么您就可以把原来的命令行改写为

    find /path -type d -exec ./doit {} \;

    如果您想省掉 ./doit 这个 shell script, 可以这么写:

    find /path -type d -exec sh -c 'command $0/*' {} \;

    (这种写法可行的原因是 "sh -c 'command' A B C ..."指令当中,$0会展开为
    A, $1会展开为B, 依此类推)

    或者您也可以略施小计使用 sed 来造出您想执行的指令行:

    find /path -type d -print | sed 's:.*:command &/*:' | sh

    如果您想减少 command 的执行次数,您可以先检查看看系统中有没有
    xargs 这个指令, xargs会从标准输入一次读取一行,并且把这些读入的资料
    合并至一个命令行内。您可以写成以下命令行:

    find /path -print | xargs command

    这样会使以下指令执行一次或多次:

    command file1 file2 file3 file4 dir1/file1 dir1/file2

    很不幸地,这并不是完美无缺或者万无一失的解法,输入 xargs 的文字行
    必须以换行字元结尾,所以当档案名称当中有奇怪的字元(如换行字元)时,
    xargs就会因此而混淆。


    3.5) 我要如何改变一个 symbolic link 的 permission 呢?

    这个问题没有意义,因为 symbolic link的 permission 根本不代表什么。
    那个 link 所指过去的档案的 permission 才有意义。


    3.6) 我要如何 "undelete" 一个档案?

    某年某月的某一天,要删除 "*.foo" 却一不小心打成了 "rm * .foo",
    结果发现竟把 "*" 都删除了。真的是欲哭无泪啊!可是你也只好把这当成
    是成长的代价了。

    当然一个称职的系统管理员应当会定期做备份。先问一问你的系统管理员看
    你不小心删除的档案是不是有备份起来。如果没有的话,嗯,继续往下看吧!

    不管你是不是真的要删除一个档案,当你下了 "rm" 以后,档案就不见了。
    在你 "rm" 一个档案,系统就不再记得你的档案是用了硬碟中的哪些 block
    了。更糟糕的是,当系统要用到更多的硬碟空间时,就优先取用这些刚放出
    来的 block。不过天底下没有不可能的事。理论上说,若你在下了 "rm" 后,
    马上把系统 shutdown,资料是就得回来的。不过,你得找一个对系统非常
    熟悉且肯花费数小时至数天的时间来帮你做这件事专家才行。

    当你不小心 "rm" 了一个档案后,第一个反应或许是为什么不用一个 alias
    或在 sh 中的 function 将 "rm" 取代掉,当你下 "rm" 只把档案搬到一个
    垃圾桶之类的地方呢?那如果不小心杀错档案就可以挽救,只是要定期清一
    清垃圾桶就好了。有两个理由。第一,大多数的人不认为这是一个好的做法。
    这么做的话你会太依赖你的 "rm",有一天到了一个正常的系统中把正常的
    "rm" 当成你的 "rm" 来用,那可能会死得很惨。第二,你会发现你花费了
    许多不必要的时间在处理垃圾桶里的东西。所以对一个初学者而言呢,用
    "rm" 的 -i选项应该就够了。

    如果你有大无畏的精神的话,那好吧,就给你个简单的答案。写一个名为
    "can" 的指令,功用是将档案移到垃圾桶里。在 csh(1) 中,将以下的东西
    放进 ".login" 里:

    alias can 'mv \!* ~/.trashcan' # junk file(s) to trashcan
    alias mtcan 'rm -f ~/.trashcan/*' # irretrievably empty trash
    if ( ! -d ~/.trashcan ) mkdir ~/.trashcan # ensure trashcan exists

    如果你想要每次 logout 时都把垃圾桶清乾净,那就把

    rm -f ~/.trashcan/*

    进 ".logout" 里。若你用的是 sh 或是 ksh,那自己试试著写写看吧!

    MIT 的雅典娜计画(Project Athena)作出了一套有
    delete/undelete/expunge/purge 的软体。这套软体可以完全取代 "rm" 而又提
    供 undelete 的功能。这个软体曾 post 在 comp.sources.misc(volume 17,
    issue 023-025)。


    3.7) 一个process 要怎样侦测出自己是否在背景状态执行?

    首先,您是否想知道您自己是在背景状态下执行,或者在交谈状态下执行?如果
    您只是想藉此决定是否该在终端上印出提示符号之类的讯息,那么更合适的方
    法应该是检查您的标准输入是否为终端机:

    sh: if [ -t 0 ]; then ... fi
    C: if(isatty(0)) { ... }

    一般来说,您无法得知自己是否在背景状态下执行。问题的根本在于不同的 shell
    与不同的 UNIX 版本对于「前景」与「背景」的定义可能有所不同。而且在最
    常见的系统上,前景与背景都有较好的定义,程式甚至可以在背景与前景之间任
    意切换!

    在没有 job control 的UNIX系统上,若要把 process 放入背景状态通常是把
    SIGINT 与 SIGQUIT 忽略掉,并且把标准输入转为"/dev/null",这是由shell处
    理的。

    在具有 job control 功能的 UNIX 系统,若shell支援 job control 功能,那么shell
    只要把 process group ID 设成跟 terminal 所属的 PGID 不同即可把 process 切
    换至背景状态;如果要把 process 切回前景状态,只要把此 process 的 PGID 设
    成跟目前 terminal 所属的 PGID 即可。如果 shell 不支援 job control 功能,则
    不管UNIX 系统是否支援 job control 的功能,shell 对 process 的处理动作都
    是一样的(也就是忽略SIGINT 与 SIGQUIT,并且把标准输入转为"/dev/null")。


    3.8) 为什么在 Bourne shell 当中,对回圈的输出入转向无法达到预期的效果?

    举个例子来说好了:

    foo=bar
    while read line
    do
    # do something with $line
    foo=bletch
    done < /etc/passwd

    echo "foo is now: $foo"

    尽管 "foo=bletch" 已经设定了 foo 的值,然而在多种系统的 Bourne shell
    上执行此 script 的时候仍会印出 "foo is now: bar"。为什么呢?因为一些
    历史因素,在 Bourne shell 当中,一个控制结构(如一个回圈,或者一个
    "if" 叙述)的重导向会造出一个新的 subshell,所以啦,在此 subshell 内
    所设定的变数当然不会影响目前 shell 的变数。

    POSIX 1003.2 Shell and Tools Interface 的标准委员会已防止上述的问题,
    也就是上述的例子在遵循P1003.2 标准的Bourne shells当中会印出
    "foo is now: bletch"。

    在一些较古老的 (以及遵循 P1003.2 标准的) Bourne shell 当中,您可以使
    用以下技巧来避免重转向的问题:

    foo=bar
    # make file descriptor 9 a duplicate of file descriptor 0 stdin);
    # then connect stdin to /etc/passwd; the original stdin is now
    # `remembered' in file descriptor 9; see dup(2) and sh(1)
    exec 9<&0 < /etc/passwd

    while read line
    do
    # do something with $line
    foo=bletch
    done

    # make stdin a duplicate of file descriptor 9, i.e. reconnect
    # it to the original stdin; then close file descriptor 9
    exec 0<&9 9<&-
    echo "foo is now: $foo"

    这样子不管在哪种 Bourne shell 应该都会印出 "foo is now: bletch"。
    接下来,看看以下这个例子:

    foo=bar

    echo bletch | read foo

    echo "foo is now: $foo"

    这个例子在许多 Bourne shell 内都会印出 "foo is now: bar",有些则会
    印出 "foo is now: bletch"。为什么呢?一般说来,一个 pipeline 里面
    的每一个部份都是在一个 subshell 中执行。但是有些系统的里 pipeline
    的最后一行如果是如 "read" 这类的内建指令,并不会另外造出一个
    subshell。

    POSIX 1003.2 对这两种作法并没有硬性规定要用哪一种。所以一个 portable
    的 shell script 不应该依赖这两种作法其中的一种。


    3.9) 我要怎么在一个 shell script 中或在背景执行 'ftp'、'telnet'、'tip' 等
    interactive 的程式呢?

    这些程式要一个 terminal interface。这是shell 所无法提供的。所以这些
    无法在 shell script 里自动执行这些程式。

    有一个就做 'expect' 的程式,可以用来做这件事,因为它提供了
    programmable terminal interface。底下的例子是用 'expect' 来帮你 login:

    # username is passed as 1st arg, password as 2nd
    set password [index $argv 2]
    spawn passwd [index $argv 1]
    expect "*password:"
    send "$password\r"
    expect "*password:"
    send "$password\r"
    expect eof

    expect 为 telnet, rlogin,debugger 和一些没有内建 command language 的
    程式提供了一个近乎自动化的方法。Expect 里面的有一用以在玩 rogue
    (一个 Unix 中的古老游戏)时取得较佳初始情况,然后将控制权还回给使用者
    的例子。用这个 script 你就能得到『成功的一半』。

    再者,有一些已经写好的程式可以帮你这类与 pseudo-tty 有关的东西,所
    以你只要?nbsp;script 中执行这些程式就可以帮你处理这些东西。

    有两个方法可以取得 'expect':
    1.送一封 email 给 library@cme.nist.gov 内容就写 "send
    pub/expect/expect.shar.Z"
    2. ftp://ftp.cme.nist.gov/pub/expect/expect.shar.Z

    另一个做法是用一个就 pty 4.0 曾贴在 comp.sources.unix volume25的东
    西。这个程式会提供一个 pseudo-tty session 给需要 tty 的程式用。若使用
    named pipe 配合 pty 4.0 来做上例,则看起来可能如下:

    #!/bin/sh
    /etc/mknod out.$$ p; exec 2>&1
    ( exec 4<out.$$; rm -f out.$$
    <&4 waitfor 'password:'
    echo "$2"
    <&4 waitfor 'password:'
    echo "$2"
    <&4 cat >/dev/null
    ) | ( pty passwd "$1" >out.$$ )

    上面的 'waitfor' 是简单的 C 程式,功用为等到 input 有与所等待的字串
    相同时再往下做。

    下面是一个更简单的做法,不过缺点是与 'passwd' 程式的互动可能无法同
    步。

    #!/bin/sh
    ( sleep 5; echo "$2"; sleep 5; echo "$2") | pty passwd "$1"


    3.10) 在 shell script 或 C 程式当中,要怎样才能找到某个程式的 process ID
    呢?

    在 shell script 当中:

    没有现成的程式可以用来查询程式名称与 process ID 之间的对应。此外,
    如果有对应的话,通常也都不太可信,因为可能会有多个 process 执行同一
    个名称的程式,而且 process 在启动之后仍可修改自己的名称。然而,如果
    您真的想要得知执行某个特定程式的所有 process, 可以利用以下命令行达
    成:
    ps ux | awk '/name/ && !/awk/ {print $2}'

    您可以把 "name" 换成您想寻找的程式名称。

    这个命令行的基本观念是分析 ps 程式的输出,然后用 awk或grep等公用
    程式来搜寻具有特定名称的文字行,然后把这些文字行当中的 PID 栏位印
    出来。值得注意的是此例的命令行用了 "!/awk/" 以避免 awk 的 process 被
    列出来。

    您可能要根据您所用的 Unix 种类来调整 ps 所用的参数。

    在 C 语言程式里面:

    在 C 的程式库里面一样没有(具有可携性)的函数可以找出程式名称与
    process IDs。

    然而有些厂商提供函数让您能读取 Kernel 的记忆体,例如 Sun 提供了
    kvm_ 开头的函数,Data General 则提供了 dg_ 开头的函数。如果您的系
    统管理员未限定 Kernel 记忆体的读取权力的话(一般只有 super user 或
    kmem 群组里的人员才能读取 Kernel 记忆体),一般使用者也可以利用这
    些特殊函数来达到目的。然而,这些函数通常没有正式的文件说明,就算有
    的话也都写得艰深难懂,甚至会随著系统版本的更新而改变。

    有些厂商会提供 /proc 档案系统,此档案系统存在的方式为一个内含多个档
    案的目录。每个档名都是一个数字,对应于 process ID,您可以开启这个档
    案并且读取关于这个 process 的资讯。再次提醒一下,有时候您会因为存取
    权限的限制而无法使用这些功能,而且使用这些功能的方式也随著系统而
    变。

    如果您的厂商并没有提供特殊的程式库或者 /proc 来处理这些事,但是您又
    想要在 C 里面完成这些功能,那么您可能要自己在Kernel 记忆体当中费心
    搜寻。如果您想看看这些功能在某些系统上是怎么做到的,可以参考 ofiles
    的原始程式,您可以从 comp.source.sources.unix 的历年归档文章当中取
    得。(有一个称为 kstuff 的套装程式曾经在 1991 年五月发表于
    alt.sources,它可以帮您在 kernel 当中搜寻有用的资讯,您可以到
    wuarchive.wustl.edu 利用匿名 ftp 取回
    usenet/alt.sources/articles/{329{6,7,8,9},330{0,1}}.Z。)


    3.11) 我要怎样经由 rsh 执行远方指令时,检查远方指令的结束状态?

    以下指令行是行不通的:

    rsh some-machine some-crummy-command || echo "Command failed"

    如果 rsh 程式本身能成功地执行,那么 rsh 程式的结束状态就是 0,但这
    也许不是您真正想要的结果。
    如果您想检查远方程式的执行状态,您可以试试Maarten Litmaath 于 1994
    年十月在 alt.sources发表的 "ersh" script,ersh 是一个呼叫 rsh 的 shell
    script,它会安排远方的机器回应远方指令的结束状态,并传回此结束状态。


    3.12) 能不能把 shell 变数传进 awk 程式当中呢?

    这个问题有两个可行的方法,第一个方法只是把程式当中需要用到此变数的
    地方直接展开,例如要得知您目前使用哪些 tty,可以使用:

    who | awk '/^'"$USER"'/ { print $2 }' (1)

    awk 程式的程式通常会用单引号括起来,因为 awk 程式里面经常会用到 $
    字元,如果使用双引号的话,shell 本身会解释这个字元。所以啦,在这种
    特殊情形下,我们想要 shell 解释 $USER 当中的 $ 字元时,就必需先用
    单引号把前半段的句子暂时括起来,然后用双引号把 $USER 括起来,再用
    单引号把随后的句子括起来。请注意,双引号在某些状况下可以略去不写,
    也就是说,可以写成:

    who | awk '/^'$USER'/ { print $2 }' (2)

    然而,如果 shell 变数的内容含有特殊字元或空白字元时,就不适用了。

    第二种把变数的设定传进 awk 的方式是利用 awk 当中一个无文件说明的
    功能,它允许您从命令列透过「假造的档案名称」来设定变数,例如:

    who | awk '$1 == user { print $2 }' user="$USER" - (3)

    由于命令行中的变数设定是在 awk 真正处理到的时候才会生效,因此您可
    以利用这种技巧让 awk 在遇到不同档名的时候做不同的动作。例如:

    awk '{ program that depends on s }' s=1 file1 s=0 file2 (4)

    请注意有些 awk 的版本会在 BEGIN 区块执行之前,就让真实档案名称之
    前所叙述的变数设定生效,但有些不会,所以您不可以依赖其中一种。

    再进一步提醒,当您指定变数的设定时,如果没有指定真实的档案名称,
    awk 将不会自动从标准输入读取,所以您要在命令之后加上一个 - 参数,
    就跟 (3) 的指令行内容一样。

    第三种做法是使用较新版的awk (nawk),您可以在 nawk 当中直接取用环
    境变数。例如:

    nawk 'END { print "Your path variable is " ENVIRON["PATH"] }' /dev/null


    3.13) 要怎样才能避免在记忆体中留下zombie processes?

    很不幸地,对于死掉的子 process 应有的行为特性并没有办法做一般化,因
    为这些特定/特定的机制会随著 Unix 的种类不同而有所差异。

    首先,在各种 Unix 上面您都必需使用 wait() 来处理子 process。也就是
    说,我还没看过有一种 Unix 会自动把结束的子 process 干掉,即使您不告
    诉它该怎么做。

    其次,在某些从 SysV 衍生的系统当中,如果您执行了 signal(SIGCHLD,
    SIG_IGN)",(嗯,事实上应该是SIGCLD 而非SIGCHLD,但大多数新出
    炉的 SysV 系统都会在表头档当中加上 #define SIGCHLD SIGCLD),那
    么子 processes 都会自动被清除得乾乾净净,您什么事都不用做。看看这个
    方式是否可行的最佳做法就是自己在机器上试试看。如果您想试著写出具可
    携性的程式码,那么依赖这种特殊处理方式可能不是好主意。不幸的是,在
    POSIX 并不允许您这样做;把 SIGCHLD 的行匦陨璩?nbsp;SIG_IGN 在
    POSIX 当中并没有定义,所以如果您要让您的程式合乎 POSIX 的要求
    时,您就不可以这样做。

    那么怎样才算是 POSIX 的做法呢?如同前面所述,您必需设定一个 signal
    的处理函数,然后让它去 wait。在 POSIX 当中 signal 处理函数是经由
    sigaction 设定,由于您只对终止的子 process 感兴趣,而不是那些 stopped
    的子 process,所以可以在 sa_flags 当中加上 SA_NOCLDSTOP。如果要
    wait 子 process 而本身不因此被挡 (block),可以使用 waitpid()。第一
    个参数必需是 -1 (代表 wait 任何 pid),第三个参数必需是 WNOHANG,这是
    最具可携性的做法,也是可能会成为未来最具可携性的写法。

    如果您的系统不支援 POSIX,那就有很多做法了。最简单的方式就是先试
    试signal(SIGCHLD, SIG_IGN) 是否可行,可以的话那就好了。如果
    SIG_IGN 无法用来强制自动收拾残骸,那么您就要自己写一个 signal 处理
    函数来收拾残骸了。要写出一个适用于每一种 Unix 的 singal 处理函数来
    做这件事是不容易的事,因为有下列不一致的地方:

    在一些 Unix 中,一个或一个以上的子 process 死时,会呼叫 SIGCHLD 的
    signal 处理函数。也就是说,如果你的 signal 处理函数只有一个 wait()
    时,并不会把所有的子 process 都收拾乾净。不过还好,我相信这类的
    Unix 都会有 wait3() 或 waitpid(),这两者都有可在 option 参数中使用
    WNOHNAG 可用来检查是否有子 process 尚待收拾。所以在一个有
    wait3()/waitpid() 的系统中,你可以一再重复使用 wait3()/waitpid()
    以确定所有的子 process 都已收拾乾净W詈檬怯?nbsp;waitpid() 因为
    它在 POSIX 标准中。

    在一些 SysV-derived 的系统中,再 SIGCHLD 的 signal 处理函数结束后,
    若还有子 process 等待清除,还是会产生 SIGCHLD signal。 因此,在大部
    份的 SysV 系统中,在 signal 处理函数里可以假设要处理的 signal 只有一
    个 

    [文章录入员:tonny]

    相关文章
  • Tru64 unix--Trucluster 安装手册
  • Tru64 UNIX系统磁盘备份与恢复
  • UNIX系统远程存取操作
  • SCO UnixWare 7下磁带机的安装与备份
  • SCO UNIX的注册警告信息
  • SCO UNIX操作系统序列号冲突
  • UNIX下format和tar易用性的一种改进方法
  • UnixWare 7 root口令遗失的解决方法
  • 在SCO UNIX系统中使用光驱
  • UNIX系统安全
  • 相关书籍:
  • tcpip详解卷三:tcp事务协议,http,nntp和unix域协议
  • Unix傻瓜书
  • SCO UNIX入门
  • 莱昂氏UNIX源代码分析
  • Unix操作手册英文版 
  • UNIX系统安全工具
  • SCO UNIX实用教程
  • 本站推荐内容

    近期主机类热搜关键词:
    美国服务器 美国服务器租用 海外服务器租用 国外服务器租用

    Unix系列
    Win9X/ME
    Win2000
    Win2003/2008
    Unix系列
    Linux系列
    WindowsXP
    WinVista/WIN7
    注册表
    其它
    电脑教程阅读排行
    ·cpio命令详细用法
    ·UNIX系统远程存取操作
    ·UNIX系统操作命令
    ·FreeBSD安装指南
    ·FTP命令使用精萃
    ·AIX常用命令
    ·用crontab命令完成SCO ...
    ·网络文件系统(NFS)使用指南
    ·shell script 浅讲
    ·Unix下 Pro*c 编译命令