UNIX Basics
original in es Javier Palacios Bermejo
es to en Javier Palacios Bermejo,Ruben Sotillo, Manuel Rodriguez
en to chinese wang zhuohao
Javier在西班牙大学致力于天文方面的哲学研究.在那里负责管理一些工作站.他所在部门的日常工作实在Unix系统上完成的.经过了一些初期问题和试验,他选择了slackware Linux. Linux显得比目前所有的其它Unix系统更好.
本文将介绍一些使用AWK的窍门。它并不是一份教材,但在其中将给出一些使用的例子。
最初,是在看了Guido Socher在linuxfocus上发表的几篇文章,才想写这篇文章。在Guido Socher的文章中有一篇是介绍文件查找和相关命令的,是我意识到并不是只有我一个人在使用命令行。很多时候漂亮的图形用户界面不能告诉我们事情是如何进行的(这是windows多年以来所延续的方法)。另一篇文章是关于规则表达式的。尽管在此文中没有过多的提及规则的表达式,你也要从awk以及其他的命令(如sed和grep)中了解到很多。
问题的关键是awk命令是否真的很有用。答案是肯定的。它将对普通用户的文本编辑有很大帮助,例如排版什么的。对于系统管理员AWK是一个非常重要的应用。随便看一下/var/yp/Makefile 或是看一下系统的初始化脚本,AWK在到处被使用着。
我已记不起最初是什么时候听到有关AWK的消息。我的一个同事要处理由Cray大量的输出结果,而这个Cray上关于AWK的联机帮助很少,他说尽管它并不会用AWK但他觉得这正是他所需要的。
很长时间以后,我们再次开始我们的工作。一个同事利用下面的AWK命令从文件中提取所有行的第一列词:
awk ' '{print $1}' file |
这是不是很简单?这样一个简单的操作并不需要象在C语言中的复杂编程。一行AWK命令就解决了。
在我们知道了如何从文件中分离一列后,我们便可以做诸如更改文件名称的操作(在files_list加.new):
ls -1 pattern | awk '{print "mv "$1"
"$1".new"}' | sh
... 另外,如果将sed和grep一起使用,那将会成为一个非常有用的工具.
ls -1 *old* | awk '{print "mv "$1" "$1}' | sed s/old/new/2 | sh
ls -l * | grep -v drwx | awk '{print "rm "$9}' | sh
ls -l | grep '^d' | awk '{print "rm -r "$9}' | sh
ls -p | grep /$
| wk '{print "rm -r "$1}'
对他进行改进.) 正如你所见到的,AWK在需要进行相同的计算时起作用。并且写一个AWK程序要比重复20此同样的操作更有意思。
确切的说,尽管我们说 awk-command
,但awk并不是我们通常所说的那种命令.awk是一种可编程语言,AWK是一种在语法的很多方面与C语言相近的表成语言。是由awk解释程序进行解释的。
关于awk解释程序自身的语法:
# gawk --help Usage: gawk [POSIX or GNU style options] -f progfile [--] file ... gawk [POSIX or GNU style options] [--] 'program' file ... POSIX options: GNU long options: -f progfile --file=progfile -F fs --field-separator=fs -v var=val --assign=var=val -m[fr] val -W compat --compat -W copyleft --copyleft -W copyright --copyright -W help --help -W lint --lint -W lint-old --lint-old -W posix --posix -W re-interval --re-interval -W source=program-text --source=program-text -W traditional --traditional -W usage --usage -W version --version Report bugs to bug-gnu-utils@prep.ai.mit.edu, with a Cc: to arnold@gnu.ai.mit.edu
你可以看到,命令可以用单引号引用在命令行运行,去掉单引号我们可以将命令写入一个文件,然后带参数-f运行。在命令行进行变量定义用到-v var=val,我们便可以增加程序的灵活性。大体上说来,AWK适合于管理表单。也就是把信息分到fields(字段)和record(记录)。
概略的说,Awk是面向表单管理的.也就是一些可以用字段和记录归类的信息.这样做的好处是纪录和字段的定义是比较灵活的。
AWK功能强大。被定义成对一行的纪录进行操作,但在这一点上并非十分严格。为了说明这一点,我们将看到下面的说明性的例子:
打印表单
也许你要打印一些得到的表单。例如,一个含有主机名、IP网络地址的列表。当这个表但是相当大的时候,读取就变得很困难,我们想以LaTeX、至少以一个比较好的格式打印出来。尽管这个列表很简单,但是打印却很麻烦:
BEGIN { printf "LaTeX preample" printf "\\begin{tabular}{|c|c|...|c|}" } |
{ printf $1" & " printf $2" & " . . . printf $n" \\\\ " printf "\\hline" } |
END { print "\\end{document}" } |
的确这不是一个普通问题,我们就要开始解决它...
(The double backslashes (\) are necessary because it's the shell escape
character)
部分输出文件
SIMBAD是一个天文目标数据库,它提供了一个形体在天空中的位置。以前每当我们想画出关于这些天体的图以进行研究。交互界面允许我用两种步骤把结果保存在文本文件里:1)为每一颗星体创建一个文件,2)用整个输入列表来填充它,这样将会得到一个很长的查询纪录日志。在我要进行第二步骤时,我用awk来区分日志。显然,这需要找到输出部分的共同点。
|
( $1 == "====>" ) { NomObj = $2 TotObj = $4 if ( TotObj > 0 ) { FS = "|" for ( cont=0 ; cont<TotObj ; cont++ ) { getline print $2 $4 $5 $3 >> NomObj } FS = " " } } |
NOTE:事实上,目标名并不被送回,它将会是相当复杂,这只不过是一个说明性例子而已。 |
Playing with the mail spool
BEGIN { BEGIN_MSG = "From" BEGIN_BDY = "Precedence:" MAIN_KEY = "Subject:" VALIDATION = "[MONTH REPORT]" HEAD = "NO"; BODY = "NO"; PRINT="NO" OUT_FILE = "Month_Reports" } { if ( $1 == BEGIN_MSG ) { HEAD = "YES"; BODY = "NO"; PRINT="NO" } if ( $1 == MAIN_KEY ) { if ( $2 == VALIDATION ) { PRINT = "YES" $1 = ""; $2 = "" print "\n\n"$0"\n" > OUT_FILE } } if ( $1 == BEGIN_BDY ) { getline if ( $0 == "" ) { HEAD = "NO"; BODY = "YES" } else { HEAD = "NO"; BODY = "NO"; PRINT="NO" } } if ( BODY == "YES" && PRINT == "YES" ) { print $0 >> OUT_FILE } } |
也许我们是在经常管理一个邮件列表,并且有一些特别的信息被提交个这个列表(例如以'[MONTH
REPORT] month , dept'为主题的)。也许在一年的年末我们忽然想要提出所有这样的信息分别存放。 这就可以用左边的awk程序处理mail spool。 使得每一份报告被存入个别的文件就意味着三行特殊的代码。 |
NOTE: 这个例子假设mail spool就是我所想的格式。此程序对我的邮件起作用。事实上我并不知道具体的格式,但这个程序在我的安装中起作用.(并且,也许在一些奇怪的情况下,他并不好用.) |
这样的一个程序,只需要用五分钟进行设计,五分钟写程序.
我也用awk实现其他功能(依据数据库中的信息自动生成页面),并且凭我所知道的,awk编程还可以做很多事。
尽情的发挥你的想象力吧。
一个问题: |
(解决办法) |
问题是awk需要一个很好的制表信息,没有空格,awk不能在定宽的列上工作。在我们自己应用awk进行输入时这并不是一个问题:选择一些特殊的字符进行分割,之后在进行修改。如果我们已经有了这样的输入表,这就会有一定的麻烦。例如下表:1234 HD 13324 22:40:54 .... 1235 HD12223 22:43:12 .... 用awk处理这个问题很困难。不行的是这竟是一个经常出现的问题。Inputs
like this sometimes are mandatory. Besides, this is quite common because data input is not
homogeneous whatsoever. 如果我们只有一列存在这样的特征,就有办法解决.(如果那位知道如何简便的管理一个表的多列,请告诉我!).
|
忽然我发现我所要处理的是最后一列,并且Awk知道当前纪录中有多少个列.因此这样就能够访问最后一列.(有时是
$9 , 有时是 $11 , 但总是 NF ).
这样的描述结果:{ printf $NF $NF = "" printf " "$0"\n" }
|
到此为止,所有的例子都是处理输入文件的所有行的。但正如手册中所说的,AWK是可以只处理部分行的。只有在满足条件的时候,才进行执行。匹配条件可以非常灵活,用一个简单的逻辑操作符所组成的条件组的标准表达式来检查内容中的字段。
争相其它编程语言一样,awk实现了所有的重要的流式控制结构,同时利用操作符和预定义的函数来处理数字和字符串。其语法与C语言相近.
AWK当然也可通过关键字function来加入用户定义的函数。除了一般的符号变量外,awk也可以操作数组。
像在所有的语言中一样,存在很多常用的函数需要在代码中经常复制和粘贴。这正是为什么引入库的概念。对于GNU的awk,可以在程序中引用库文件。但这并不在本文的讨论范围之内。
当然,awk其它一些可以用作相同目的的工具一样强大,但是它的最大优点是可以在很短的时间内制作出小程序来解决我们的问题。
AWK非常适合以下目的的需求:需要从数据中一行一行的读出内容,并对字符和格式进行操作。
象/etc/passwd 这样的文件就可以用awk对他进行格式处理。对于这样的操作awk是再合适不过的了。
当然在这方面并不是只有AWK。Perl也是一个非常有力的竞争者,但还是值得去了解一些AWK的技巧。
这只不过是一些很基础的命令,也没有很好的整理,你可以在更广泛的阅读中找到更多的东西。
通常在所有的unix书中都提及到awk,但很少有书中仔细的对其进行介绍。所以我们最好浏览所有我们手头的书,你永远不知道省么时候可以找到一些有用的东西。