⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unix faq

📁 UNIX FAQ 中文版
💻
📖 第 1 页 / 共 2 页
字号:
         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 有关的东西,所
         以你只要? 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 的行

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -