电脑网络频道 >>>

首 页 | 网络安全 | 搜索引擎 | 网络应用 | 建站常识 | 网络编程 | 硬件课堂 | 操作系统 
首页>>>电脑网络>>>操作系统>>>正文
unix精彩问答

  上一篇:Linux常用命令   收录日期:2005-9-22 7:23:37
 
 

之一:

这篇文章以下问题的解答:

1.1) 谁帮助你将做出这个 faq 的?
1.2) 当有人提及''rn(1)'' 或 ''ctime(3)'' 的时候,刮弧里的数目意谓什么呢?
1.3) 一些奇怪的 unix 指令名字的由来?
1.4) "comp.unix.questions" 和 "info-unix" mailing list 之间的gateway 是如何运作的?
1.5) 请建议一些有用的 Unix, C 相关书籍.
1.6) 以前在这 FAQ 中的发音表到那去了?


1.1) 谁帮助你将做出这个 faq 的?

这个文件是最初的几个 FAQ 之一, 编纂于 1989 年七月。整个编辑工作几乎都是 Steve Hayman 做的。 我只是接管这份文件的维护。

我们非常感谢 Usenet 读者提出的问题,反应,更正和提议。

特别感谢 Maarten Litmaath, Guy Harris 和 Jonathan Kamens,他们都贡献良多。

这个文件中的第 5 部份(shells)几乎完全是 Matthew Wicks<wicks@dcdmjw.fnal.gov> 写的。

这个文件中的第 6 部份(各种 Unix)几乎完全是 Pierre (P.) Lewis<lew@bnr.ca> 写的

我尽可能的把每个问题的作者与最后更新的日期放在问题的开端。很不幸地,因为我最近才开始这样做, 许多的资讯已遗失。我也疏于保存为问
题补充最新资料者的名单。对那些有贡献而没有得到应有的荣誉者, 在此致歉。

我将此文件转为 *roff 格式(ms 与 mm 两种 macro 都有)。AndrewCromarty把它转换成 Texinfo 格式。这些格式化的版本可由 anonymous
ftp 于
_blank>ftp.wg.omron.co.jp 的 pub/unix-faq/docs 取得.


1.2) 当有人提及''rn(1)'' 或 ''ctime(3)'' 的时候,刮弧里的数目意谓什么呢?

看起来像是 function call, 不过, 不是。 这些数目字是指 Unix 手册中文件所在的章节。当你打 "man 3 ctime" 时, 表示是要查阅在第
3节中ctime 的内容。

传统 Unix 手册的分节法

1 User-level commands
2 System calls
3 Library functions
4 Devices and device drivers
5 File formats
6 Games
7 Various miscellaneous stuff - macro packages etc.
8 System maintenance and operation commands

一些 Unix 版本使用非数字的章节名字。举例来说, Xenix 的指令用"C"而功能用"S"。 一些比较新的 Unix 版本得用 "man -s# title" 而
非"man # title"。每一节都有一个简介, 以 # 代表节数, "man # intro" 就可以读第 # 节的简介。

有时为了区别指令和相同名字的常式或系统呼叫数字是必需的。 举例来说,你的系统可能有"time(1)", 有关 ''time'' 这个测量所费时间指令
的说明,也有 "time(3)", 关于 ''time'' 这个用来决定目前时间的副常式的说明。你可以用 "man 1 time" 或 "man 3 time" 来选择要看哪
一"time" 的说明。

或许你系统会有其它的章节或在细分的次章节(subsection),像 Ultrix 就有 3m, 3n, 3x 与 3yp。


1.3) 一些奇怪的 unix 指令名字的由来

awk = "Aho Weinberger and Kernighan"

这个语言以作者 Al Aho, Peter Weinberger 和 Brian Kernighan 的姓来命名。

grep = "Global Regular Expression Print"

grep 来自 ed 的列印所有符合某 pattern 指令

g/re/p

"re" 代表 regular expression

fgrep = "Fixed GREP".

fgrep □找固定的字串。"f" 不是代表 "fast" - 事实上, "fgrep foobar *.c" 通常比 "egrep foobar *.c" 来得慢(有点意外吧, 不信
的话, 自己试试喽)。
尽管如此,Fgrep 仍然有可取之处,在档案中搜寻字串的时候,Fgrep能处理的字串数目较 egrep 多。

egrep = "Extended GREP"

egrep 用比 grep 更 fancy 的 regular rexpression。许多人始终只用 egrep,因为它用的 algorithm 比 grep 或 fgrep 用的高级,而
且通常是三个程式中最快的。

cat = "CATenate"

catenate 是一个艰深难懂的单字,意思是"把它连成一串", 这就是"cat" 这个指令对一个或多个档案所做的处理。

请不要跟 C/A/T 混淆了,C/A/T 是指电脑辅助排版系统(Computer Aided Typesetter)。

gecos = "General Electric Comprehensive Operating Supervisor"

不过,当通用电器 (GE) 的大型系统部门卖给 Honeywell 的时候,Honeywell 就把 GECOS 的 E 拿掉了。

目前 Unix 的密码档里面仍保有 "pw_gecos" 这个栏位。这个名字是从古早的年代沿用过来的。

Dennis Ritchie 曾经说过:

"有时候我们会把印表输出或整批工作丢到 GCOS 机器。密码档里面的 gcos 栏位是用来隐藏 $IDENT 卡片上的资讯,这样做不够优雅"。


nroff = "New ROFF"
troff = "Typesetter new ROFF"

这些字都是从"roff"衍生的, roff 是重写 Multics 上的 runoff 程式得来的 (runoff 的意思就是"印出文件")。

tee = T

这是管线工人的术语,代表 T 型的管线分叉器。

bss = "Block Started by Symbol" (由符号启始的区块)

Dennis Ritchie 曾说过:

这个缩写也许有其他说法,但事实上我们采用这个缩写的本意是"Block Started by Symbol"。它是 FAP 上的虚拟指令,FAP(Fortran
Assembly [-er?] Program) 是指 IBM 704-709-7090-7094这种机型的组译器。这个指令可定义自己的标号,并且预留一定数目的字组空间。
还有另一个虚拟指令 BES,是 "Block Ended by Symbol",跟 BSS 指令几乎一样,不同点在于标号是定义在预留字组空间尾端的位址 + 1 的
地方。在这些机器上,Fortran 的阵列是以反方向储存,而且阵列的索引是从 1 算起。

这种用法是合理的,因为这跟 UNIX 上标准的程式载入器一样,程式码当中并非真的放入这一整块预留空间,而是先用一个数目表示,在载入时
才真的把所需的预留空间定出来。

biff = "BIFF"

这个指令是用来设定当您有新邮件进来时,是否要通知您。这是柏克莱大学校园内一只狗的名字。

我可以确定这个名称的起源,如果您有兴趣的话,Biff 是 Heidi Stettner 养的宠物,想当年 Heidi (还有我,跟 Bill Joy) 都还是UCB的
研究生时,早期的 BSD 版本还在发展中。Biff 受到流连于Evans Halls 这些人的喜爱,也因为它会对前来的邮差吠叫而闻名;因此就
以 biff 当作指令的名称。(这是卡内基美浓大学的 Eric Cooper 证实的)

rc (像是 ".cshrc" 或 "/etc/rc" 中的 rc 这两个字母) = "RunCom"

"rc" 是取自 "runcom", 来自麻省理工学院在 1965 年发展的 CTSS系统。相关文献曾记载这一段话 ''具有从档案中取出一系列命令来执
行的功能;这称为 "run commands" 又称为 "runcom",而这种档案又称为一个 runcom (a runcom)。''

Brian Kernighan 与 Dennis Ritchie 告诉 Vicki Brown 说 "rc" 也是Plan 9 作业系统 shell 的名字。



Perl = "Practical Extraction and Report Language"
Perl = "Pathologically Eclectic Rubbish Lister"

Perl是 Larry Wall 所发展的一种相当受欢迎的语言, Perl 在处文字,process,与档案时非常便利,可以说是兼得 shell 与 C 之长。想
知道更多关于Perl 的讯息,请看 Usenet newsgroup comp.lang.perl。

Don Libes 的 "Life with Unix" 一书里有更多这类的珍闻轶事。


1.4) "comp.unix.questions" 和 "info-unix" mailing list 之间的gateway 是如何运作的?

"info-unix" 与 "unix-wizards”分别是 comp.unix.questions 和comp.unix.wizards 的 mailing-list 版。Mailing list 与
newsgroup的内容应该是相同的

要加入或退出任一个 mailing list, 请送 email 给info-unix-quest@brl.mil或
unix-wizards-request@brl.mil。切记要加入或退出
mailing list 时是送给"*-request@brl.mil" 。也请您耐心等候因为不会马上有回应。

底下就是 mailing list 的维护者 Bob Reschly 所提供关于这些 mailing list的详细细节。

==== postings to info-UNIX and UNIX-wizards lists ===

我个人不对送到 mailing list 的内容作管制,任何送到这个 mailing list 的信件都会贴到相对应的 news group。BRL 只是单纯的转送。
在此 mailing list上的 Internet 使用者,要送文章到 newgroup 上时请送到 info-UNIX 或UNIX-wizards, ''-request'' 是要的信是要送
给 mailing list 的维护者看的。

在此 mailing list 上的 Internet 使用者会收到两类的讯息,一种是单独一篇的讨论文章,另一种则是集结多篇讨论精华的文摘。从
Internet 或者BITNET (透过 Bitnet ←→ Internet 转换程式)寄往 BRL 的讯息都会转发一份给 mail list 当中的每一个使用者。


从 USENET 发出来的文章则以每天汇整一次的方式寄给 mailing list 当中的所有成员。BITNET 的网路交通跟 Internet 的网路交通很像。
主要的不同点在于:对于 mailing list 内所有 BITNET 的收件人,我只要维护一个电子邮件地址,让这个地址所在的收件程式维护所有收件
人的资讯,并且自动转寄所有文章给 mailing list 上的每一个订阅者即可。

在 USENET 上的订阅者只会读到各自独立的讯息,所有发自 Internet 的讯息则转送至我们位于 USENET 上的机器,然后贴至合适的讨论区。
很不幸地,这些透过转换程式贴出去的文章,发件人会变成 news@brl-adm,这是转换软体目前尚未解决的先天限制。

至于读者群方面,USENET 是一个拥有广大读者群的地方,我估计约有数千部主机与数万名使用者参与 USETNET。BRL 所维护的主要 list 约
有250 个,大约有百分之十是本地的转送 list。我不太清楚 BITNET 方面的转送数目,不过如果要让我猜的话,数目大约跟主要 list 一样。平均一个list 在一个星期内要送出 150K 到 400K 的资料。


1.5) 请建议一些有用的 Unix, C 相关书籍。

Mitch Wright (mitch@cirrus.com) 维护一份 Unix 和 C 相关书籍一览表,里面包含简介与短评。目前在他的表上有 167 本ftp.rahul.net
(192.160.13.1) 的 "pub/mitch/YABL/yabl" 就是这份一览表。 要加入新的内容或提供建议送 email 给
mitch@cirrus.com

Samuel Ko (kko@sfu.ca) 维护一份 Unix 相关书籍表。这个列表只包含推荐书,因此比较短。 这份表是分类的列表, 如果你正在寻找特定条
件类型的书, 这份表无疑是较为合适的。rtfm.mit.edu 的"pub/usenet/news.answers/books/unix" 就是此表。要加入新的内容或提供建议
送 email 给
kko@sfu.ca

如果你不能使用 anonymouse ftp, email 到 "ftpmail@decwrl.dec.com"信的内容就写 "help",然后你就会收到一份教你如何以 email 取
得anonymous 的信件。


1.6) 以前在这 FAQ 中的发音表到那去了?

当 1989 本文件开使时, 它包含了一份 Carl Paukstis<carlp@frigg.isc-br.com> 原作,由 Maarten Litmaath 所维护的一份包罗万象的
发音表。后来它功成身退了,因为发音与 "Unix questions" 这个主题不是真的有关。

若你碰到一些不知该怎么读的字, 请参考 Eric S. Raymond
eric@snark.thyrsus.com 所维护的 Jargon。

/* 译注
_blank>ftp//ftp.csie.nctu.edu.tw/pub/GNU/jarg320.txt.gz 是普通文字版 Jargon */

若你还是坚持要以前那份发音表,
_blank>ftp.wg.omron.co.jp (133.210.4.4) 的"pub/unix-faq/docs/Pronunciation-Guide" 就是啦

 

之二:

本篇文章回答以下问题

2.1) 我要怎么删除以 ''-'' 字元开头为档名的档案?
2.2) 我要怎样才能把档名当中含有特殊字元的档案删除?
2.3) 我要如何列出整个目录树呢?
2.4) 要怎么设定 prompt 才会显示出目前所在的目录?
2.5) 当我在写 shell script 时,要如何从 terminal 读入字元?
2.6) 怎么样把 "*.foo" 改名为 "*.bar" 呢?怎样把档案名称改成小写呢?
2.7) 为什么我用 "rsh host command" 会有一些奇怪的讯息出现?
2.icon<a_cool.gif src="/UpLoadFiles/NewsPhoto/con_cool.gif" border=0> 我要怎要用程式或者是 shell script 中设定目前所用的 shell 的环境
2.9) 我要如何将 csh 的 stdout 与 stderr 导向到不同的胤侥兀?nbsp;
2.10) 我如何在 .cshrc 中判断是否在 login shell 中?
2.11) 在 shell 中要用怎样的 pattern 来表示除了 "." 与 ".." 外的所有档
2.12) 在 Bourne shell script 里要怎么找出最后一个参数?
2.13) 为什么有人说 $PATH 里不可以放 ''.'' 呢?
2.14) 在 shell script 中要怎么让终端机发出声音呢?
2.15) 为什么我不能用 "talk" 与我在某机器上的朋友交谈呢?
2.16) 为什么我月历是错的?

2.1) 我要怎么删除以 ''-'' 字元开头为档名的档案?

找一个方法让档案名称开头不要是 ''-'' 就可以了,最简单的方法就是使用

rm ./-filename

(当然,我们假设 "-filename" 位于目前的目录)。这个方法可以避免让其
他指令解释 "-"。

有许多指令,特别是呼叫 "getopt(3)" 的参数剖析常式的程式,会接受一
个 "--" 的参数,代表「这是最后一个选项」,此后出现的项目都不再是选
项,因此您的 rm 可能会接受这个 "rm -- -filename" 这种写法。有些不用
getopt() 的 rm 程式也会以同样的方式处理单一字元 "-",因此您也可以试
试 "rm - -filename"。


2.2) 我要怎样才能把档名当中含有特殊字元的档案境?nbsp;

如果这个「特殊字元」是 ''/'',请跳到这题的结尾;如果这个特殊的字元是
一个 '' 或者控制字元或者中文字,请继续往下读。

典型的解法是

rm -i some*pattern*that*matches*only*the*file*you*want

这样子的话 rm 会在要删除符合你给的条件的档案前,要你确定,不
过若你的 shell 会将每个字元的第八个 bit 变成零,那以中文作档
名的档案可能就删除不掉了!



rm -ri .

这样子的?nbsp;rm 会删除目前目录下的所有档案,而在删除一个档案之
前会问你是否要删除此档。不过很不幸的,并非每一个版本的 rm 都
能这么用。再者,就算能用的话,这么做的话会把目前所在目录的所
有子目录都找进去,可能要用 "chmod a-x" 避免使子目录无法搜寻才
能避免可怕的后果。要做 "rm -r" 或含有万用字元的 "rm" 前请先深
呼吸,搞清楚自己是在做什么!



find . -type f ... -ok rm ''{}'' \;

"..." 是一堆用以辨识档案名称的述词,譬如在找出一有问的档案的
inode 为何后,用

find . -num 12345 -ok rm ''{}'' \;



find . -inum 12345 -ok mv ''{}'' new-file-name \;

删除或改名。 选项 "-ok" 是告诉 find 要执行指令前先要求你确认
。若你能确定所下的指令没有问题,或者怕所要处理档案有奇怪的字
元印出来会使萤幕乱七八糟,那用选项 "-exec" 就不会先要求你的确
认。

那当档案名称里含有 ''/'' 时要怎么办呢?

这类档案是很特别的情形,并且只会因为 kernel 的 bug 而发生(通
常是在写 NFS 的时候,没有把从远端机器来的档案名称中不合规定的
字元过滤掉)。我们第一件要做的事情就是,试著去了解为什么这个
问题会如此奇怪。

UNIX 的目录其实就只是单纯的档名和 inode number 的成对组合。
举例来说,目录包含了如下的资讯

filename inode

file1 12345
file2.c 12349
file3 12347

理论上挥?nbsp;''/'' 和 ''\0'' 两个字元不能用在档案名称中,
因为它们有以下的特殊用途:

''/'' :用来分隔目录名称及档案名称。
''\0'' :用来当档名的终结字元。

非常、极端、很不幸的,某些厂商做出来的 NFS 在回应远端机器的要
求时,会很白痴地造出含有斜线(/)的档名。例如,当某人在 Mac
或其他非 Unix 机器透过 NFS 造一个以日期为名称的档案到你的
Unix 中。那么,你的 Unix 目录看起来可能就会像这个样子:

filename inode

91/02/07 12357

我们前面所提过的 ''find'' 或 ''rm'' 都无法删除这个档案,因为这些或
其他的 Unix 程式都会强制把 ''/'' 当作前述的分隔字元解释。

其实,任何一般的程式都会试著做 unlink("91/02/07"),而这对
kernel 来说,它的意义是 "unlink 目录 91 下的子目录 02 中的档
案 07",但是,我们并没有这样的档案,我们有的是一个名叫
"91/02/07" 的档案在目前的目录中。这是个极细微但极重要的区别。

这时该怎么办呢?首先回到产生这种乱七八糟档名的 Mac,试试
看 NFS daemon 要不要让你改成不含 ''/'' 的档名。如果不行,那就得
找你的系统管理者帮忙了。请他试试以下几种方法之一

1. 用 "ls -i" 找出蛋傅?nbsp;inode number,umount 掉这个
file system 然后以 "clri" 将这个 inode 清除,然后
祈求“fsck" 的成功。这个作法会删除这乱七八糟档名的
档案。

2. 若还想保存这个档案的资料,试试以下的做法:

-在那乱七八糟档名的档案所在之目录的亲目录底下建一
个子目录,将旧的目录下能搬动的档案都搬到新的目录
里。
-以 "ls -id" 取得旧目录的 inode number
-unmount 掉这个 file system, 用 "clri" 清掉那个
目录的 inode
-"fsck" 那个 file system
-从新 mount 上那个 file system
-将新的目录改名为旧的目录名
-从 lost+found 下找回那个档案,改个好名字,放回原
来的目录。

3.若你有一个叫做 "fsdb" 的程式,那你可以试试看喽!


2.3) 我要如何列出整个目录树呢?

底下有几种做法自己挑一个吧:

ls -R (not all versions of "ls" have -R)
find . -print (should work everywhere)
du -a . (shows you both the name and size)

若你要找的是特定的档案,例如说是档名结尾为 ".c" 者,可用

find . -name ''*.c'' -print

"find" 是一个很强很好用的程式。值得一学。


2.4) 要怎么设定 prompt 才会显示出目前所在的目录?

这得视你的 shell 而定。有些 shell 很容易,有些 shell 很难,有些根
本办不到。

C Shell (csh)

将以下的东西加入你的 .cshrc 里。

alias setprompt ''set prompt="${cwd}% "''
setprompt # to set the initial prompt
alias cd ''chdir \!* && setprompt''

假如你有用 pushd 与 popd, 把底下的东西也加进去。

alias pushd ''pushd \!* && setprompt''
alias popd ''popd \!* && setprompt''

若你的 C shell 没有 $cwd 这个变数,那就得用 `pwd` 代替之。

若你想要的只是 prompt 里有目前所在目录的最后一个成分
("mail%" 而?nbsp;"/usr/spool/mail%") 则用

alias setprompt ''set prompt="$cwdt% "''

有些旧版的 csh 将 && 和 || 的意义弄反了。你可以试试看:

false && echo bug

若结果是印出 "bug",那就把 && 和 || 对调,或找一个没有这种
bug 的 csh 来用。

Bourn Shell (sh)

如果你有较新版的 Bourn Shell(SVR2 或更新的版本),那么你就可
以用一个 shell function 来造你自己的命令,譬如 "xcd":

xcd() { cd $* ; PS1="`pwd` $ ";}

如果你的 Bourn Shell 是比较旧的版本,也是可以做到,但是方法比
较复杂。这里提供一个方法。把以下的内容加入你的 .profile:

LOGIN_SHELL=$ export LOGIN_SHELL
CMDFILE=/tmp/cd.$ export CMDFILE
# 16 is SIGURG, pick a signal that''s not likely to be
used
PROMPTSIG=16 export PROMPTSIG
trap ''. $CMDFILE'' $PROMPTSIG

然后把以下的部份写成一个可执行的 script(不需要缩排),名字就
叫做 "xcd",放在你的 PATH 中

xcd directory - change directory and set prompt
by signalling the login shell to read a command file

cat >${CMDFILE?"not set"} <<EOF
cd $1
PS1="\`pwd\`$"
EOF
kill -${PROMPTSIG?"not set"} ${LOGIN_SHELL?"not set"}

那么,现在就可已用 "xcd /some/dir" 来改变工作目录了。

Korn Shell (ksh)

把下面这行加入你的 .profile 中:

PS1=''$PWD $ ''

如果你只想显示最后一个部分,那么就用

PS1=''${PWD##*/} $ ''

T C shell (tcsh)

Tcsh 是常用的 csh 加强版,增加了一些内建变数(及许多其他的功
能):

%~ the current directory, using ~ for $HOME
%/ the full pathname of the current directory
%c or %. the trailing component of the current directory

所以你可以直接用

set prompt=''%~''

BASH (FSF''s "Bourne Again Shell")

$PS1 中的 \w 表示工作目录的完整路径(以 ~ 表示 $HOME);\W 则
是表示工作目录的最后一个部份。所以,只要把前面所提有关 sh 和
ksh 的方法做以下的修改

PS1=''\w $ ''

PS1=''\W $ ''

2.5) 当我在写 shell script 时,要如何从 terminal 读入字元?

在 sh 中,你可以用 read。通常是使用在回圈,如下例:

while read line
do
...
done

在 csh 中,则用 $Content$lt;:

while ( 1 )
set line = "$Content$lt;"
if ( "$line" == "" ) break
...
end

很可惜的,csh 并没有方法判断空白行和档案结尾(end-of-file)的不同。

如果你要用 sh 从 terminal 读一个字元,那么你可以试试

echo -n "Enter a character "
stty cbreak # or stty raw
readchar=`dd if=/dev/tty bs=1 count=1 2>/dev/null`
stty -cbreak
echo "Thank you for typing a $readchar ."


2.6) 怎么样把 "*.foo" 改名为 "*.bar" 呢?怎样把档案名称改成小写呢?

为什么 "mv *.foo *.bar" 不对呢? 想想 shell 是怎样把万用字元展开的
吧。 在 mv 读取参数前 "*.foo" 与 "*.bar" 就已经展开了。"mv *.foo
*.bar" 在各种不同的 shell 会有不同的结果。 Csh 的话会印出 "No
match",因为找不到 "*.bar"。 Sh 则是会执行 "mv a.foo b.foo c.foo
*.bar",也就是说如果只有在有一名为 "*.bar" 的子目录存在时 mv 才会
认为执行成功,不过就算成功也不是你所预期的结果。

正确的做法是用你所用的 shell 提供的回圈来做。若你的系统中有
"basename" 这个指令:

C Shell
foreach f ( *.foo )
set base=`basename $f .foo`
mv $f $base.bar
end

Bourne Shell
for f in *.foo; do
base=`basename $f .foo`
mv $f $base.bar
done

有些 shell 会提供就自己的变数替代功能,那就可以不用 "basename",
而用更简单的回圈了:

C Shell

foreach f ( *.foo )
mv $f $fr.bar
end

Korn Shell

for f in *.foo; do
mv $f ${f%foo}bar
done

如果没有 "basename" 可用或是胍鱿癜?nbsp;foo.* 改名为 bar.* 之类的
事,那么可以用其他的方法如 "sed" 把原来的档案名称做分隔的动作,但
是回圈的想法是一样的。你也可以利用 "sed" 把档名转换成 "mv" 的命令
,然后再把这些命令转给 "sh" 执行。如下:

ls -d *.foo | sed -e ''s/.*/mv & &/'' -e ''s/foo$/bar/'' | sh

在 1990 年 4 月时,Vladimir Lanin 把他自己写的一个叫 "mmv" 的程式
post 到 comp.sources.unix (Volumn 21, issues 87 and 8icon<a_cool.gif src="/UpLoadFiles/NewsPhoto/con_cool.gif" border=0>,这个程式
就能够把这件事处理得很好。 你可以这样使用:

mmv ''*.foo'' ''=1.bar''

以上所提的 shell 中的回圈也可以用来做档案名称的大、小写转换。你可
以用改档名的方式把大写档名改为小写:

C Shell
foreach f ( * )
mv $f `echo $f | tr ''[A-Z]'' ''[a-z]''`
end

Bourne Shell
for f in *; do
mv $f `echo $f | tr ''[A-Z]'' ''[a-z]''`
done

Korn Shell
typeset -l l
for f in *; do
l="$f"
mv $f $l
done

如果你还希望能处理含有特殊字元(空白或其他的奇怪字元)的档名,那
么你最好用:

Bourne Shell

for f in *; do
g=`expr "xxx$f" ''xxx\(.*\)'' | tr ''[A-Z]'' ''[a-z]''`
mv "$f" "$g"
done

''expr'' 不管档名里有没有特殊字元都会印出档名。

有些版本的 "tr" 需要用 ''['' 和 '']'',有些则不必。不过,不管是不是一
定要用 ''['' 与 '']'' 的 "tr",加了总是没有害处。

若你的系统里有装 "perl",那你可以用 Larry Wall 写的这个多用途改档
名的程式。

#!/usr/bin/perl
#
# rename script examples from lwall
# rename ''s/\.orig$//'' *.orig
# rename ''y/A-Z/a-z/ unless /^Make/'' *
# rename ''$_ .= ".bad"'' *.f
# rename ''print "$_ "; s/foo/bar/ if <stdin> =~ /^y/I'' *

$op = shift;
for (@ARGV) {
$was = $_;
eval $op;
die $@ if $@;
rename($was,$_) unless $was eq $_;
}


2.7) 为什么我用 "rsh host command" 会有一些奇怪的讯息出现?

(这里所指的 "rsh"[也可能是 "remsh" 或 "remote"] 是 remote shell,
而不是在有些系统中名为 "rsh" 的 restricted shell,这两者天差地远
了!)

若你在远端的帐号用的是 C shell,那远端的主机会帮你启动一个 C
shell 来完成你所下的那个 ''command'',这个 shell 会读取你在远端的
.cshrc 档。若你的 .cshrc 中有 "stty" 或 "biff" 这类不适合 non-
interactive shell 的指令。那就可能会有你所意想不到的结果,举例来

说,若你把

stty erase ^H
biff y

放在你的 .cshrc 档里面你可能会得到类似以下的奇怪讯息

% rsh some-machine date
stty Can''t assign requested address
Where are you?
Tue Oct 1 092445 EST 1991

若你使用 "at" 或 "cron",那可能也会得到类似的错误讯息。

不过没关系,解决的方法非常简单。若你的 ".cshrc" 里面有一堆只有在
interactive shell 中才有用的 operation,那就将那些 operation 都用
以下的做法包起来:

if ( $?prompt ) then
operations....
endif

因为在一个 non-interactive 中不应该也没有必要去设定 "prompt"。

还有一些只有在开启一个 login session时才有用的东西,最好搬到
".login" 中去。

2.icon<a_cool.gif src="/UpLoadFiles/NewsPhoto/con_cool.gif" border=0> 我要怎要用程式或者是 shell script 中设定目前所用的 shell 的环境
变数或改变所在的目录?

若没有做一些特殊安排是做不到的。因为,当我们造出一 child process
时,此 process 会继承其 parent 的变数与所在的目录。在这个 child
process 只能改到自己的变数与所在目录而无法影响到其 parent。

要达到此目的,parent process 要与 child process 有所沟通。当
child process 要改变变数值时得把要改变的变数及其内容写到一个讲好
的地方,让 parent process 去读取, 并改变 parent process 的变数。


另一个做法则是写一个 shell script,然后在 Bourne shell 或 Korn
shell 中用 ".",在 C shell 中用 source 去执行那个 shell script。
若此 sript 名为 "myscript"


在 Bourne shell 或 Korn shell 中就用

. myscript

在 C shell 中则用

source myscript

若你想做的只是要改变所在目录或是设定一个环境变数,那使用 C shell
中的 alias 或是 Bourne/Korn shell 中的函数就可达成你的目的。可参
考"要怎么设定 prompt 才会显示出目前所在的目录"一节中的做法。

Thomas Michanek (xtm@telelogic.se) 提供一个更详细的解答(
_blank>ftp//ftp.wg.omron.co.jp/pub/unix-faq/docs/script-vs-env)。


2.9) 我要如何将 csh 的 stdout 与 stderr 导向到不同的地方呢?

在 csh 中,用 ">" 将 stdout 导向,用 ">&" 则能将 stdout 与 stderr
一起导向。可是不能只单独把 stderr 转向。最好的方法是

( command >stdout_file ) >&stderr_file

以上的命令会开一个 subshell 执行 "command";而这个 subshell 的
stdout 则被转向到 stdout_file,同时这个 subshell 的 stdout 和
stderr 则都被转向到 stderr_file,但是因为 stdour 已经先被转向了,
所以 stderr 就会被转到 stderr_file 了。

如果你只是单纯的不想把 stdout 做转向,那么就用 sh 来帮你吧。

sh -c ''command 2>stderr_file''


2.10) 我如何在 .cshrc 中判断是否在 login shell 中?

当有人这么问的时候,通常要问的是

要如何判断是否是一个 interactive shell? 或是问要如何判断是否是
最上层的 shell ?

若你是要问 "是否在 login shell 中"(注:就是在做完 .cshrc 后,会
再去做 .login),那么你也许用 "ps" 和 "$" 随便弄一弄,就能知道了
。因为通常 login shells 的名字在 "ps" 看起来都是由 ''-'' 做开头的。
如果你是真的对另外两个问题感兴趣,那么这里有个方法可以让你在
.cshrc 中判断。

if (! $?CSHLEVEL) then
#
# This is a "top-level" shell,
# perhaps a login shell, perhaps a shell started up by
# ''rsh machine some-command''
# This is where we should set PATH and anything else we
# want to apply to every one of our shells.
#
setenv CSHLEVEL 0
set home = ~username # just to be sure
source ~/.env # environment stuff we always want
else
#
# This shell is a child of one of our other shells so
# we don''t need to set all the environment variables again.
#
set tmp = $CSHLEVEL
@ tmp++
setenv CSHLEVEL $tmp
endif

# Exit from .cshrc if not interactive, e.g. under rsh
if (! $?prompt) exit

# Here we could set the prompt or aliases that would be useful
# for interactive shells only.

source ~/.aliases


2.11) 在 shell 中要用怎样的 pattern 来表示除了 "." 与 ".." 外的所有档案?

这个问题看来容易。因为你可以用

* 表示所有不是以 "." 为开端的档案

.* 表示所有以 "." 为开端的档案,但是这样会把 "." 和 ".." 也包
含进来,但是通常你并不会想把这两个也含进来。

.[!.]* 这只有比较新的 shells 才能用;某些 shells 用 "^" 代替 "!";
而符合 POSIX 标准的 shells 一定苡?nbsp;"!",但是大部份也都能接
受 "^";所有具可移植性的应用程式都不应该在 "[" 之后紧接著没被
quota 起来的 "^")表示所有以 "." 为开头并且第二个字元不是 "."
的档案;但是这样却会漏掉 "..foo" 这类的档案。

.??* 表示所有以 "." 为开头且档名长度至少为 3 的档案,这样大概
就能避开 "." 和 ".." 了,但是却还是会漏掉 ".a" 这类的档。

所以想要正确地表示除了 "." 与 ".." 之外所有的档案,你必须要用到 3
个 patterns(如果你没有像 ".a" 这样的档案,那你可以去掉第一个
pattern):

.[!.]* .??* *

或者你也可以用一两个外部程式和 backquote substitution。这样就很完
美了:


`ls -a | sed -e ''/^\.$/d'' -e ''/^\.\.$/d''`

(or `ls -A` in some Unix versions)

不过即使是这样做,碰上档名里面含有换行字元, IFS 字元,或是万用字
元仍然是没辄。


2.12) 在 Bourne shell script 里要怎么找出最后一个参数?


Martin Weitzel <@mikros.systemware.demartin@mwtech.uucp>
Maarten Litmaath <maart@nat.vu.nl>
提供的答案:

若你能确定参数不会超过九个的话,可用:

eval last=\${$#}

在符合 POSIX 标准的 shell 里,不管有多少个参数都可用上述的方法。

底下方法是一定有用的:

for last
do

done

更一般性的做法是

for i
do
third_last=$second_last
second_last=$last
last=$i
done

若你想做的是将最后一个参数去除或是将一堆参数的顺序反过来或是取用
第 N 个参数。底下是一个不用造出 subprocess 只用 shell 组建功能的
做法:

t0= u0= rest=''1 2 3 4 5 6 7 8 9'' argv=

for h in '''' $rest
do
for t in "$t0" $rest
do
for u in $u0 $rest
do
case $# in
0)
break 3
esac
eval argv$h$t$u=\$1
argv="$argv \"\$argv$h$t$u\"" # (1)
shift
done
u0=0
done
t0=0
done

# now restore the arguments
eval set x "$argv" # (2)
shift

这个例子可以用到 999 个参数,应该够用了吧?仔细看看(1)与(2)标示的
地方,想办法说服你自己不管参数里面有什么奇怪的字元这两行都不会出
差错。

要找第 N 个参数,用:

eval argN=\$argv$N

要将参数的顺序反过来,标示为(1)的那一行必须改成

argv="\"\$argv$h$t$u\" $argv"

自己练习最后一个参数去除的方法。

若允许呼叫外部指令这类造出 subprocess 的做法,代志就更好办了。
底下是找出 argvN:

N=1

for i
do
eval argv$N=\$i
N=`expr $N + 1`
done

要将参数的顺序反过来还有一个不用造出 subprocess,有更简单的方法。
这个方法也可以用来去除最后一个参数, 不过要注意的是 argvN 不在是
原来的第 N 个参数:

argv=

for i
do
eval argv$#=\$i
argv="\"\$argv$#\" $argv"
shift
done

eval set x "$argv"
shift


2.13) 为什么有人说 $PATH 里不可以放 ''.'' 呢?

背景知识: 环境变数 PATH 是一串用冒号隔开的目录。当你下一个指令而
没有指定所在的目录,例如 "ls" 而非 "/bin/ls",则你的 shell 就会在
PATH 所指定的目录中去找寻指令。


你可以在 PATH 里面放入目前所在的目录 "." 。或者,在 PATH 中加入一
个空的目录,这两者是等效的

for csh users

setenv PATH /usr/ucb/bin/usr/bin
setenv PATH ./usr/ucb/bin/usr/bin

for sh or ksh users

PATH=/usr/ucb/bin/usr/bin export PATH
PATH=./usr/ucb/bin/usr/bin export PATH

把 "." 放在 PATH 中是很方便的,若要执行 "./a.out" 只要打 "a.out"
即可,但是这么做会有大麻烦。

当把 "." 放在 PATH 的最前面情况下。若你目前所在目录是如 "/tmp" 这
样大家都可以写的地方。如果有别的使用这放了一个名为 "ls" 的程式在
那里,而你打入 "ls" 那你可能就死得非常难看了。

把 "." 放到 PATH 的结尾是个比较好的做法:

setenv PATH /usr/ucb/bin/usr/bin.

这么一来,当你在 "/tmp" 中打 "ls" 保?nbsp;shell 就会先找 "/usr/ucb",
"/bin" 与 "/usr/bin" 里的 "ls"。减少了一点危险。不过仍然不是百分之
百安全。假如你是个笨拙的打字者,有一天你把 "ls -l" 打成 "sl -l",
而又有一个聪明的使用者能猜到这种常见的打字错误,在 "/tmp" 底下放
了一只 "sl",你还是得死。所以啊,千万要小心。


  下一篇:Linux操作系统下6个应急处理小常识 
收录日期:2005-9-22 7:23:37 
相关新闻:
 
   特别申明:本站绝大部分文章与作品均收集于互联网或网友自行上传,如有侵权,请主动与我们联系,如属实,我们会及时删除。同时深圳生活网不对文章及作品使用后果负任何连带责任。谢谢合作!


 热 点 排 行

·Google纪录你的一言一行
·搜集的Sql一些常用的语句
·挽救烧坏金手指的显卡实录
·电脑死机故障分析
·QQ使用技术后续版之QQ搞怪十
·QQ使用技术后续版之QQ搞怪十
·Google新鲜技巧玩法
·电脑保护误区面面观
·使用xmldom在服务器端生成静
·音箱挑选过程中的7个注意事项
·实例演练ASP+XML编程
·非常不错的Javascript脚本
·动态效果DHTML
·Javascript实现上传的图片按
·怎样才能把我的网站加入Goog
·为什么在Google上搜不到我的
·Google的网站收录和排名
·体验Windows XP中超强syskey
·Linux程序应用开发环境和工具
·windows xp 家庭用户内存优化