UNIX 的主要慨念是希望透过管线(piping)和重导(redirection)的观念将所有简单的指令串连起来而可以足够应付真实生活上所有复杂的工作。 让我们来看看下面的例子﹐我将只解释比较复杂的例子;其他简单的例子﹐请利用上面我所介绍的观念和说明文件(man pages)﹐相信您一定可以很快的进入情况。
问题: 如果只使用 ls
这个指令来显示文档﹐如果文档太多的话﹐常常就一飞而逝﹐还来不及看完﹐结果就被卷上去了:
解决方案:
$ ls | less
问题: 我有一个文档﹐里面包含了许多文字﹐我想将之反向排序后列印出来:
解决方案:
$ cat myfile.txt | sort -r | lpr
问题: 我的资料档内有许多重复的资料﹐我要如何删除重复的资料呢?
解决方案:
$ sort datafile.dat | uniq > newfile.dat
问题: 我有一个叫做 'mypaper.txt' 或是 'mypaper.tex' 的文档﹐或是类似这样的文档名称﹐但是我忘记我将她们存放在什么地方了﹐我要如何找到她们呢?
解决方案:
$ find ~ -name "mypaper*"
说明: find
是一个非常有用的指令﹐她可以列出树状目录下的所有文档﹐(在本例中﹐我们是从 ~
这里开始寻找﹐也就是 $HOME 的目录)。
她的输出结果可以透过许多条件设定﹐而达到许多不一样的需求。例如 -name
。
问题: 我想找一个文档内的某一个字﹐例如 'entropy'﹐我要如何作呢?有没有类似像 SEARCH
这种指令呢?
解决方案: 有的, 试试看 grep 这个指令:
$ grep -l 'entropy' *
说明:*表示所有的文档。
问题: 在某个地方﹐的某个文档的内容有 'entropy' 这个字, 我想知道是哪一个文档﹐且放在哪里﹐
在 VMS 上我可以使用 search entropy
[...]*.*;*
, 但是 grep
这个指令不可以收寻子目录﹐现在我要如何解决呢?
解决方案:
$ find . -exec grep -l "entropy" {} \; 2> /dev/null
说明: find .
输出从目前这个目录下所有的文档(包含这个目录下所有子目录)﹐
-exec grep -l "entropy"
是对每一笔由 find 传出来的文档重复执行执行(represented by {}
),
\
为结束这个指令。如果您觉得的些东西太可怕了﹐没错﹐不过您可以试著写写下面的 Script。
#!/bin/sh # rgrep: recursive grep # 递回式撷取 if [ $# != 3 ] then echo "Usage: rgrep --switches 'pattern' 'directory'" exit 1 fi find $3 -name "*" -exec grep $1 $2 {} \; 2> /dev/null
说明: grep
就像 search
, 结合了
find
﹐我们得到了两者的精华。
问题: 我有一个资料文档﹐这个文档共有两列档头(header lines)(也就是说﹐第三笔资料才是我真正的资料)﹐ 如果我想要撷取每笔资料的第二和第五栏的资料﹐我需要写一个 Fortran 的程序吗?
解决方案: 不需要。来看看这个具有杀伤力的指令!
$ awk 'NL > 2 {print $2, "\t", $5}' datafile.dat > newfile.dat
说明: awk
这个指令实际上可以说是一种程序语言:上面的意思是说:
在 datafile.dat
这个文档里﹐从文档的第三行开始的每一行﹐印出每一行的第二和第五栏位﹐
以 tab 为分隔符号。学会了 awk
一定会让您事半功倍的。
问题: 我从 FTP 站下载了 ls-lR.gz
这个文档﹐想要察看文档内容。
对每一个子目录而言﹐她有一行写说 "total xxxx", 其中 xxxx 表示文档大小(kbytes)
我想知道所有 xxxx 值的总和﹐我要如何作呢?
解决方案:
$ zcat ls-lR.gz | awk ' $1 == "total" { i += $2 } END {print i}'
说明: zcat
可以列出 .gz
的文档内容。然后将 zcat 得到的结果转送(pipe)到
awk
。看到了吧!了解 awk 真的对您有很大的帮助喔。RMP!
问题: 我已经写了一只 myprog
的 Fortran 的程序﹐可以计算由命令列传进来的文档的资料﹐
可是﹐我有很多个资料档需要输入到这只程序﹐每一个文档将会有一个结果文档。但是每次都要输入档名实在很烦人﹐
在 VMS 上﹐我需要写一个啰唆的命令档(command file)才可以解决﹐那么在 Linux 上呢?
解决方案: 只要一个小小的 Script 就可以解决了。修改您的程序﹐让您的程序可以预定读入 'mydata.dat
' 这个文档﹐
将结果输出到萤幕(stdout), 然后编辑下面的 Script:
#!/bin/sh # myprog.sh: run the same command on many different files # usage: myprog.sh *.dat for file in $* # for all parameters (e.g. *.dat) do # append the file name to result.dat echo -n "${file}: " >> results.dat # copy current argument to mydata.dat, run myprog # and append the output to results.dat cp ${file} mydata.dat ; myprog >> results.dat done
问题: 我希望将所有文档内的 `geology' 字替换成 `geophysics' ﹐我需要手动编辑吗?!
解决方案: 不需要。 下面的 Shell Script 可以帮您办到:
#!/bin/sh # replace $1 with $2 in $* # usage: replace "old-pattern" "new-pattern" file [file...] OLD=$1 # first parameter of the script NEW=$2 # second parameter shift ; shift # discard the first 2 parameters: the next are the file names for file in $* # for all files given as parameters do # replace every occurrence of OLD with NEW, save on a temporary file sed "s/$OLD/$NEW/g" ${file} > ${file}.new # rename the temporary file as the original file /bin/mv ${file}.new ${file} done
问题: 我有一些文档﹐我不知道她们的文档长度﹐我必须移除这些文档内的倒数第二和倒数第三行﹐需要手动吗?
解决方案: 当然不需要﹐还是使用 Shell Script:
#!/bin/sh # prune.sh: removes n-1th and n-2th lines from files # usage: prune.sh file [file...] for file in $* # for every parameter do LINES=`wc -l $file | awk '{print $1}'` # 计算总共有几行 LINES=`expr $LINES - 3` # LINES = LINES - 3 head -n $LINES $file > $file.new # 输出前 LINES 行 tail -n 1 $file >> $file.new # 再将最后一行附加到文档最后 done
希望以上这些实例增加您不少的食欲...