11. 真实生活示例

UNIX 的核心思想是有许多简单的命令可以通过管道和重定向链接在一起,以完成非常复杂的任务。请看以下示例。我只会解释最复杂的示例;对于其他示例,请学习以上章节和 man 手册。

问题: ls速度太快,文件名飞快闪过。

解决方案:

$ ls | less

问题:我有一个包含单词列表的文件。我想反向排序并打印它。

解决方案:

$ cat myfile.txt | sort -r | lpr

问题:我的数据文件有一些重复的行!我该如何摆脱它们?

解决方案:

$ sort datafile.dat | uniq > newfile.dat

问题:我有一个名为 'mypaper.txt' 或 'mypaper.tex' 或类似的文件,但我不记得我把它放在哪里了。我该如何找到它?

解决方案:

$ find ~ -name "mypaper*" 

解释find是一个非常有用的命令,可以列出目录树中的所有文件(从~在这种情况下)。它的输出可以被过滤以满足几个标准,例如-name.

问题:我在此目录中有一个包含单词 'entropy' 的文本文件,有什么类似SEARCH?

解决方案:是的,试试

$ grep -l 'entropy' *

问题:在某处我有包含单词 'entropy' 的文本文件,我想知道是哪些以及它们在哪里。在 VMS 下我会使用search entropy [...]*.*;*,但是grep无法递归子目录。现在怎么办?

解决方案:

$ find . -exec grep -l "entropy" {} \; 2> /dev/null

解释find .输出从当前目录开始的所有文件名,-exec grep -l "entropy"是要在每个文件上执行的操作(由{}), \终止命令。如果你认为这种语法很糟糕,你是对的。

作为替代方案,编写以下脚本

#!/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

解释grepsearch一样工作,并将其与find我们兼得两者之长。

问题:我有一个数据文件,它有两行标题行,然后每行有 'n' 个数据,不一定均匀分布。我想要每行的第 2 个和第 5 个数据值。我应该写一个 Fortran 程序吗...?

解决方案:不用。这样做更快

$ awk 'NL > 2 {print $2, "\t", $5}' datafile.dat > newfile.dat

解释:命令awk实际上是一种编程语言:对于从第三行开始的每一行,在datafile.dat,打印出第二个和第五个字段,用制表符分隔。学习一些awk---它可以节省大量时间。

问题:我下载了一个 FTP 站点的ls-lR.gz以检查其内容。对于每个子目录,它都包含一行写着 "total xxxx",其中 xxxx 是目录内容的大小(千字节)。我想获得所有这些 xxxx 值的总和。

解决方案:

$ zcat ls-lR.gz | awk ' $1 == "total" { i += $2 } END {print i}'

解释zcat输出.gz文件的内容并通过管道传输到awk,请您阅读其 man 手册 ;-)

问题:我编写了一个 Fortran 程序,myprog,用于从数据文件中计算一个参数。我想在数百个数据文件上运行它并获得结果列表,但每次都询问文件名很麻烦。在 VMS 下我会编写一个冗长的命令文件,在 Linux 下呢?

解决方案:一个非常短的脚本。让你的程序查找数据文件 'mydata.dat' 并在屏幕 (stdout) 上打印结果,然后编写以下脚本

#!/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 脚本

#!/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

问题:我有一些数据文件,我不知道它们的长度,必须删除它们倒数第二行和倒数第三行。呃... 手动吗?

解决方案:不,当然不是。编写这个脚本

#!/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}'`  # number of lines in file
  LINES=`expr $LINES - 3`                 # LINES = LINES - 3
  head -n $LINES $file > $file.new        # output first LINES lines
  tail -n 1 $file >> $file.new            # append last line
done

我希望这些例子引起了您的兴趣...