一起学shell之(七)产生脚本以及Awk的惊人表现


行参数分析、在远程主机上运算、环境变量、工作记录、并行处理、使用eval的运行时语句(runtime statement)执行、草稿文件、shell函数、用户定义初始文件、以及安全性议题考虑的范例。

软件构建自动化:由于unix可运行在多种平台上,因此在构建软件包时,较常见的实现方式是从源代码开始安装,而非直接安装二进制包。

顶层configure脚本通常由GUN的autoconf命令,通过configure.in或configure.ac文件里的规则列表自动产生,执行该脚本时,有时得加上一些命令行选项,便能产生定制的C/C++头文件,通常叫config.h衍生自Makefile.in(模版文件)的一个定制的Makefile.并时有时候还会有其它文件。

Makefile目标的标准集已详述于<The GNU Coding Standards>中有all(全部构建)、check(执行验证测试)、clean(删除不需要的中间文件)、distclean(恢复目录到它的原始发布),以及install(在本地系统上安装所有必需的文件)。

被安装的文件位于Makefile文件里prefix变量所定义的默认树状结构目录下,并且可在配置时使用--prefix=dir命令行选错行设置,或是通过一个本地系统范围的定制文件提供、默认的prefix为/usr/local,但无权限的用户可能使用$HOME/local或是用$HOME/`arch`/local更好,其中arch是一条命令,它会显示定义平台的简短说明。GNU/LInux与Sun Solaris提供的是/binarch。在基它平台下,安装自己的实作程序时,通常只是使用简单的shell脚本包装(wrapper),再搭配适当的echo命令。

煮酒品茶:这就是我们经验源码安装的一些标准定义吧。有空瞧瞧nginx他的模版。原作有对这个进行很强烈的讲解并自己编写了一个码。我就不打写了,等全完之后再回头看几次,并进行一个更新,可能的话去看看nginx是如何做的。

AWK的惊人表现:

Awk设计的目的:简化一般文本处理的工作。

属于POSIX的一部分。

AWK命令行:

Awk的调用可以定义变量、提供程序并且指定输入文件:

Awk [ -F fs ]  [ -v var=value ... ] 'program' [ -- ] \ 
[ var=value ... ] [ file(s) ] 
Awk [ -F fs ]  [ -v var=value ... ] -f program'file [ -- ] \ 
[ var=value ... ] [ file(s) ] 

短程序通常是直接在命令行上提供,而比较长的程序,则委托-f选项指定,遇到需连接被指名的程序文件以得到完整的程序时,则可重复使用此选项,这是包含共享awk代码的程序库存之方便用法。选项需置于文件名以及一般var=value赋值的前面。

-- 是特殊选项:指出awk本身已没有更进一步的命令行选项,任何接下来的选项都可被你的程序使用。

-f选项是用来重新定义默认字段分隔字符,且一般惯例将它作为第一个命令行选项,紧接在-F选项后的fs参数是一个正则表达式,或是被提供作为下一个参数。字段分隔字符也可设置使用内建变量FS所指定的:

初始化的-v选项必须放在命令行上直接给定的任何程序之前,它们会在程序启动之前以及处理任何文件之前生效,在一命令行程序之后的-v选项会被解释为一个文件名可(能是不存在的)

在命令行上其它地方的初始化会在处理参数时完成,并且会带上文件名。例如:

Awk '{ ... }' Pass=1 *.tex Pass=2 *.tex

处理文件的列表两次,第一次是Pass设为1,第二次将它设为2.

注:使用字符串值进行初始化无须用引号框起来,除非shell要求这样的引用,以保护牸字符或空白。支持正则。

注:特殊文件名-(连字号)表示标准输入。/dev/stdin为标准输入,/dev/stderr标准错误输出,/dev/stdout标准输出。

Awk程序模型:

Awk把输入流看作一连串记录的集合,每条记录都可进一步细分为字段,通常,一行一条记录,而字段则由一个或多个非空白字符的单词组成。然而,是什么构成一条记录和一个字段,完全是由程序员控制,且它们的定义,甚至可以在处理期间更改。

一个awk程序是一对以模式(pattern)与大括号框起来的操作(action)组合而成的。

输入会自动地由一个输入文件切换到下一个,且awk本身通常会处理每个输入文件的打开、读取和关闭,以允许用户程序专心致力于记录的处理。虽然模式多半是数据或字符串表达式,不过awk以保留字BEGIN与END提供两种特殊模式。

程序元素:awk处理数字与字符串数据,提供了标量(scalar)与数组(array)两种变量以保存数据、数字与字符串表达式。还提供了一些语句类型以处理数据:赋值、注释、条件、函数、输入、循环及输出。

由#号注释单行,单条语句多行可用反斜杠。

字符串的比较,用的是传统的关系运算符。返回1为真,0为假。Awk并无特殊的字符串接续运算符。两个连续字符串,会自动地连接在一起。

支持正则表达式,有两个运算符:~(匹配)与!~(不匹配)

正则表达式常量可以用引号或斜杠加以定介:"ABC" ~ /^[A-Z]+$/ 等同于"ABC" ~ "^[A-Z]+$" ,如果在引号字符串里正好需要有字面意义的引号,则应以反斜杠("...\"...")保护。

Awk处理字符串转数据的函数,s = "123" 接着n = 0  + s ,便将数据123赋值给n了。(并不适用)

Awk的数值运算符[图]

 

Awk可用括号以控制计算顺序。

一、复合式,像/=这样,以左边运算数作为右这的第一个去处数。N /=3 便是n=n/3

二、赋值的结果用来作为另一个表达式的部分表达式:(赋值运算符为右结合性)

Awk里一般常用到的内建标量变量

 

命令行参数

Awk对于命令行的自动化处理,awk通过内变量ARGC(参数计数)与ARGV(参数向量,或参数值),让命令行参数可用。

在awk程序化模式中,通过输入文件隐含循环的每一次迭代,会处理单一记录(record),通常是一行文本,记录可进一步再侵害为更小的字符串,叫做字段(field)。

FS的默认值为单一空格,它接受特殊的解释方式 。一个或多个空白字符(空格与制表字符)以及行的开头与结尾的空白,都将被忽略。因此a b 与a b相同。

[root@bogon 8csjb]# cat awkfs 
a b c d
a	b	c	d	e	f
[root@bogon 8csjb]# awk -F" " '{print $1,$2,$3,$4,$5,$6}' awkfs 
a b c d  
a b c d e f

匹配单个空格设置FS  = "[ ]"

字段可以特殊名称$1\$2、...、$NF供awk程序使用。字段引用无须是固定的,有必须的话,它们还可以转换(通过截断)为整数值:假定k为3,则值$k\$(1+2)、$(27/9)、以及$3、都引用到第三个字段。特殊字段名称$0引用到当前的记录,初始值是从输入流中读取,且记录分隔字符不是记录的一部分。引用到0到NF范围以上的字段编号是不会有错。

模式与操作构成awk程序的核心,awk的非传统数据驱动程序模式,使得它更吸引用户使用,也成就了许多awk程序的简洁形式。

模式由字符串与或数值表达式构建而成:一昊它们计算出当前输入记录的值为非零(真),则实行结合性的操作。如果模式是正则表达式,则意指此表达式会被来与整个输入记录进行匹配。

操作段落是可选地接在一个模式之后,也就是操作所在之处:它标明了如何处理该记录。

常见用法:一个print语句里包含了以逗号隔开的零或多个表达式,每个表达式会被计算,有必要时会转换为一个字符串,且以输出字段分隔字符OFS的值将输出分隔后传送到标准输出,接在最后项目之后的是输出记录分隔字符ORS的值。

-------------------------------------------------------------------------------------------
[root@bogon ~]# echo '1 2 3 4 5 a' |awk '{ OFS ="abc"; print $1,$2,$3,$4,$5,$6}'
1abc2abc3abc4abc5abca
[root@bogon ~]# echo '1 2 3 4 5 a' |awk '{ OFS ="\n"; print $1,$2,$3,$4,$5,$6}'

[root@bogon ~]# echo '1 2 3 4 5 a' |awk '{ OFS =" "; print $1,$2,$3,$4,$5,$6}'

改变输出字段分隔字符而没有指定任何字段,不会改变$0;,如果我们更改输出字段分隔字符,并指定至少一个字段(即强制以新的字段分隔字符重新组合记录)结果为
 

[root@bogon ~]# echo '1 2 3 4 5 a' |awk '{ OFS ="\n";  print $0}'
[root@bogon ~]# echo '1 2 3 4 5 a' |awk '{ OFS ="\n"; $1=$1; print $0}'

如果程序为空,则awk不会读取任何输入并立即退出,所以我们可以匹配cat

除开NUL字符问题,awk可以轻松取代cat

大量实例:

要将原始数值及它们的对数打印为单栏的数据文件,可使用:

Awk '{ print $1, log($1) }' file(s)

打印文本文件5%行左右的随机样本。使用虚拟承受机产行函数。

Awk 'rand() <0.05' file(s)

在以空白分隔字段的表格中,报告第n栏的和:

Awk -v COLUMN=n '{ sum += $COLUMN} END { print sum }' file(s)
------------------------------------------------------------------------------------
[root@bogon 8csjb]# echo "2" |awk -v COLUMN=n '{ sum += $COLUMN} END { print sum }'
2	  #字符视为0
[root@bogon 8csjb]# echo "2" |awk -v COLUMN=n '{ sum += $COLUMN} END { print sum/2 }'
1	 #算术运算符
[root@bogon 8csjb]# awk '/print/' awk	 #等同于grep 'print' awk
print "ARGC =", ARGC
print "ARGV[" k "] = [" ARGV[k] "]"
查找100-150行
[root@bogon 8csjb]# awk '(1 <= FNR) && (FNR <=15) && /print/ {print FILENAME ":" FNR ":" $0 }' awk
awk:2:	print "ARGC =", ARGC
awk:4:	 print "ARGV[" k "] = [" ARGV[k] "]"
用sed如下:
[root@bogon 8csjb]# sed -n  1,15p -s awk |egrep 'print'
print "ARGC =", ARGC
print "ARGV[" k "] = [" ARGV[k] "]"
[root@bogon 8csjb]# awk 'BEGIN { FS = "print"; OFS = "&" } { $1=$1;print}' awk
BEGIN{
& "ARGC =", ARGC
for (k=0; k<ARGC; k++)
& "ARGV[" k "] = [" ARGV[k] "]"
}
删除已排序流里的重复行:
Sort file(s) |uniq
Sort file(s) | awk 'Last !=$0 { print } { Lst =$0 }'
将回车字符/换行字符的行终结,一致转换为以换行字符作为行终结。
Sed -e 's/\r$//' file(s)
Sed -e 's/^M$//' file(s)	 #^M ctrl+M
Mawk ''BEGIN { RS = "\r\n" } {print }' file(s)  
要将单空格的文本行,转换为双空格的行。
-------------------------------------------------------------------------------------------------------
[root@bogon 8csjb]# sed -e 's/$/\n/' awk
BEGIN{
print "ARGC =", ARGC
for (k=0; k<ARGC; k++)
print "ARGV[" k "] = [" ARGV[k] "]"
}
[root@bogon 8csjb]# awk 'BEGIN { ORS = "\n\n"} {print}' awk 	#记录分隔符ORS
[root@bogon 8csjb]# awk 'BEGIN { ORS = "\n\n"} 1'  awk
[root@bogon 8csjb]# awk '{ print $0 "\n"}'   awk
[root@bogon 8csjb]# awk '{ print; print "" }'   awk
将双空格行转换为单空格一样是很容易的:
[root@bogon 8csjb]# awk '{ print; print "" }'   awk|awk 'BEGIN {RS ="\n *\n" } {print}'
BEGIN{
print "ARGC =", ARGC
for (k=0; k<ARGC; k++)
print "ARGV[" k "] = [" ARGV[k] "]"
}
寻找超过限制长度72个字符的行
egrep -n '^.{73,}' file(s)
[root@bogon 8csjb]# awk 'length($0) >3 {print FILENAME ":" FNR ":" $0 }' awk 
awk:1:BEGIN{
awk:2:	print "ARGC =", ARGC
awk:3:	for (k=0; k<ARGC; k++)
awk:4:	 print "ARGV[" k "] = [" ARGV[k] "]"
查找html标题内容
Awk -v ORS=' ' -v RS='( \n)' '/<title *>/, /<\/tiltle *>/' file(s) | sed -e '$@</title *> *@&\n@g'

可以更新批量下载网页那东西了,取标题页。@与/没区别。特别环境特别使用。

 

语句:程序语言必须支持连续性的、条件式的及重复的执行。

连续执行如:a=1;b=2;c=3

条件式执行:

If (expression)

Statement1

Else

Statemnt2

重复执行:(while、do) (for、for)

注意:因为浮点算术通常不精确,所以避免在for语句表达式里,计算非整数的值。

其它的流程控制语句

只针对此记录略过更进一步的模式检查。

使用Next语句。

针对当前输入文件略过更进一步的模式检查。

Gawk与近期的nawk都提供nextfile语句,它会使得当前输入文件立即关闭且模式的匹配会从命令行上下一个文件里的记录重新开始。

用户控制的输入

Awk直接处理命令行上标明的输入文件,意指绝大多数的awk程序都不必自己打开与处理文件。它也可以通过awk的getline语句来做这件事情。

基础数值函数

相关内容