当前位置:首页 > 技术与方案 > Linux及应用

UNIX常见问题

(2012-09-26 15:49:18)

问: 在执行 rsh 的时候怎样才能不等远端指令执行结束就回到 shell?
答:如果您在远端使用csh: rsh machine -n 'command >&/dev/null

问: 我如何获得文件建立的时间?
答:很遗憾,因为文件建立的时间并未存储在任何地方,所以无法得知。
关于一个文件您只能查到最后修改的时间(ls -l),最后读取的时间(ls -lu) 与 inode 改变的时间。man pages 命令将最后一个时间当成是建立的时间,这种说法是错的。因为 mv、ln、chmod、chmod、chown、 chgrp等操作都会改变这个时间。

问: 怎样有效使用截断功能?
答: 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
 -无法使用截断功能来增加文件长度
 -执行截断操作会移动文件指标

问: 为什么执行 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/*' {} 。

问:我如何“undelete”一个文件?
答: 不管您是不是真的要删除一个文件,当您使用了“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,则自己试试看吧!

问:一个process 怎样能测出自己是否在后台执行?
答:若您想知道某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”)。 

 问:我怎样在一个 shell script 中或在后台执行 'ftp'、'telnet'、'tip' 等 interactive程序呢?
答:在 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 的程序库里面一样没有(具有可携性)的函数可以找出程序名称与process IDs。 然而有些厂商提供函数让您能读取 Kernel 的记忆体,例如,Sun 提供了 kvm_ 开头的函数,Data General 则提供了 dg_ 开头的函数。如果您的系统管理员未限定 Kernel 记忆体的读取权力的话(一般只有 super user 或 kmem 群组里的人员才能读取 Kernel 记忆体),一般使用者也可以利用这些特殊函数来达到目的。然而,这些函数通常没有正式的文件说明,就算有的话也都写得难于理解,甚至会随着系统版本的更新而改变。
有些厂商会提供 /proc 文件系统,此文件系统存在的方式为一个内含多个文件的目录。每个文件名都是一个数字,对应于 process ID,您可以开启这个文件并且读取关于这个 process 的信息。再次提醒一下,有时候您会因为存取权限的限制而无法使用这些功能,而且使用这些功能的方式也随着系统而变。
如果您的厂商并没有提供特殊的程序库或者 /proc 来处理这类事,但是您又想要完成这些功能,那么您可能要自己在Kernel 记忆体中耐心地搜索。

问:我怎样使用 rsh 执行远程命令时,检查远程命令的结束状态?
答:以下命令行是行不通的:rsh some-machine some-crummy-command || echo“Command failed”。如果 rsh 程序本身能成功地执行,那么 rsh 程序的结束状态就是 0,但这也许不是您真正想要的结果。如果您想检查远程程序的执行状态,您可以试试“ersh”script,ersh 是一个呼叫 rsh 的shell  script,它会控制远程的机器回应命令的结束状态,并仅返回此结束状态。
问:能不能把 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。
问:要怎样才能避免在记忆体中留下zombie processes?
答:很不幸,对于死掉的子 process 具有的行为特性并没有办法做一般化,因为特定的机制会随着Unix 的种类不同而有所差异。
 首先,在各种 Unix 上面您都必需使用 wait() 来处理子 process。也就是说,我还没看过有一种 Unix 会自动把结束的子 process 删除掉,即使您不告诉它该怎么做。
其次,在某些从 SysV衍生的系统当中,如果您执行了 signal(SIGCHLD,  SIG_IGN),(嗯,事实上应该是SIGCLD 而非SIGCHLD,但大多数新出炉的 SysV系统都会在表头文件中加上 #define SIGCHLD SIGCLD,那么子 process都会自动被清除,您什么事都不用做。看看这个方式是否可行的最佳做法就是自己在机器上试试看。如果您想试着写出具有可携性的程序码,那么依赖这种特殊处理方式可能不是好方法。不幸的是,在 POSIX并不允许您这样做;把 SIGCHLD 的行为特性设成 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,这是最具可携性的做法,也是可能会成为未来最具有可携性的写法。

更多
关闭窗口 打印 
网站首页    -    联系我们    -   收藏本站    -    网站地图                                                               客户服务热线:0571-85023000
本网站所有网页信息已申请知识产权和著作权保护,版权归四海光纤公司所有,未经授权禁止任何人复制或镜像,违者必究。
公司主营:杭州光纤光缆视频会议系统,是专业的通信网络工程、视频会议系统建设专家

中华人民共和国备案号:浙ICP备10018243号