通用线程:Awk 实例( 三 )


{ if ( $1 == "foo" ) { if ( $2 == "foo" ) { print "uno" } else { print "one" } } else if ($1 == "bar" ) { print "two" } else { print "three" }}
使用 if 语句还可以将代码:
! /matchme/ { print $1 $3 $4 }
转换成:
{ if ( $0 !~ /matchme/ ) { print $1 $3 $4 }}
这两个脚本都只输出不包含 matchme 字符序列的那些行 。此外,还可以选择最适合您的代码的方法 。它们的功能完全相同 。
awk 还允许使用布尔运算符 "||"(逻辑与)和 "&&"(逻辑或),以便创建更复杂的布尔表达式:
( $1 == "foo" ) && ( $2 == "bar" ) { print }
这个示例只打印第一个字段等于 foo 且第二个字段等于 bar 的那些行 。
数值变量!
至今,我们不是打印字符串、整行就是特定字段 。然而,awk 还允许我们执行整数和浮点运算 。通过使用数学表达式,可以很方便地编写计算文件中空白行数量的脚本 。以下就是这样一个脚本:
BEGIN { x=0 }/^$/ { x=x 1 }END { print "I found " x " blank lines. :)" }
在 BEGIN 块中,将整数变量 x 初始化成零 。然后,awk 每次遇到空白行时,awk 将执行 x=x 1 语句,递增 x 。处理完所有行之后,执行 END 块,awk 将打印出最终摘要,指出它找到的空白行数量 。
字符串化变量
awk 的优点之一就是“简单和字符串化” 。我认为 awk 变量“字符串化”是因为所有 awk 变量在内部都是按字符串形式存储的 。同时,awk 变量是“简单的”,因为可以对它执行数学操作,且只要变量包含有效数字字符串,awk 会自动处理字符串到数字的转换步骤 。要理解我的观点,请研究以下这个示例:
x="1.01"# We just set x to contain the *string* "1.01"x=x 1# We just added one to a *string* print x# Incidentally, these are comments :)
awk 将输出:
2.01
有趣吧!虽然将字符串值 1.01 赋值给变量 x,我们仍然可以对它加一 。但在 bash 和 python 中却不能这样做 。首先,bash 不支持浮点运算 。而且,如果 bash 有“字符串化”变量,它们并不“简单”;要执行任何数学操作,bash 要求我们将数字放到丑陋的 $( ) ) 结构中 。如果使用 python,则必须在对 1.01 字符串执行任何数学运算之前,将它转换成浮点值 。虽然这并不困难,但它仍是附加的步骤 。如果使用 awk,它是全自动的,而那会使我们的代码又好又整洁 。如果想要对每个输入行的第一个字段乘方并加一,可以使用以下脚本:
{ print ($1^2) 1 }
如果做一个小实验,就可以发现如果某个特定变量不包含有效数字,awk 在对数学表达式求值时会将该变量当作数字零处理 。
众多运算符
awk 的另一个优点是它有完整的数学运算符集合 。除了标准的加、减、乘、除,awk 还允许使用前面演示过的指数运算符 "^"、模(余数)运算符 "%" 和其它许多从 C 语言中借入的易于使用的赋值操作符 。
这些运算符包括前后加减(i、--foo)、加/减/乘/除赋值运算符( a =3、b*=2、c/=2.2、d-=6.2) 。不仅如此 -- 我们还有易于使用的模/指数赋值运算符(a^=2、b%=4) 。
字段分隔符
awk 有它自己的特殊变量集合 。其中一些允许调整 awk 的运行方式,而其它变量可以被读取以收集关于输入的有用信息 。我们已经接触过这些特殊变量中的一个,FS 。前面已经提到过,这个变量让您可以设置 awk 要查找的字段之间的字符序列 。我们使用 /etc/passwd 作为输入时,将 FS 设置成 ":" 。当这样做有问题时,我们还可以更灵活地使用 FS 。
FS 值并没有被限制为单一字符;可以通过指定任意长度的字符模式,将它设置成规则表达式 。如果正在处理由一个或多个 tab 分隔的字段,您可能希望按以下方式设置 FS:
FS="t "
以上示例中,我们使用特殊 " " 规则表达式字符,它表示“一个或多个前一字符” 。

推荐阅读