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
希望以上这些实例增加您不少的食欲...