AWK语言第二版 1.6控制流语句 1.7数组

1.6 控制流语句

Awk提供了if-else语句来做决策控制,还提供了一些语句来做循环,这些都是从C语言借来的,只能用在动作里面。

If-Else语句

下面的程序用来计算时薪超过30美元的员工的总收入和平均收入,里面使用了 if 来防止计算平均收入时的除0错误。

$2 > 30 { n++; pay += $2 * $3 }

END     { if (n > 0)
             print n, "high-pay employees, total pay is", pay,
                      "  average pay is", pay/n
          else
             print "No employees are paid more than $30/hour"
       }

用emp.data做输入,输出为

No employees are paid more than $30/hour

在这if-else语句中,先对if后面的条件求值。如果为真,则执行第一个print语句,否则执行第二个print语句。注意我们用逗号将一个长语句分成了几行。

另外还要注意,如果if语句值控制单条语句,则不需要大括号,但如果是多条语句,就需要加上大括号了。下面这个版本对if和else控制的部分都加上了大括号,使它们的控制范围看起来更清晰。通常来说,这样的冗余是一种好的风格。

$2 > 30 { n++; pay += $2 * $3 }

END     { if (n > 0) {
             print n, "employees, total pay is", pay,
                      "  average pay is", pay/n
          } else {
             print "No employees are paid more than $30/hour"
          }
        }

While语句

while语句包含一个条件和一个主体。当条件为真时,主体里面的语句会被重复执行。下面的程序用于计算一笔投资,在某个收益率的情况下,其价值在若干年内如何增长。其中使用了公式 value = amount (1 + rate)years。

# interest1 - compute compound interest
#   input:  amount  rate  years
#   output: compounded value at the end of each year

{   i = 1
    while (i <= $3) {
        printf("\t%.2f\n", $1 * (1 + $2) ^ i)
        i++
    }
}

在这个例子里,条件就是 while 后面括号内的表达式;而主体由条件后面大括号内的两条语句组成。printf 语句里,规格字符串中的 \t 表示 tab制表符, 而 ^ 是幂运算符。从 # 井号开始到行尾的文本属于注释。Awk程序会忽略注释,但注释是给程序的读者看的,用于帮助理解程序。

可以给这个程序输入三个数字,分别代表投资金额、收益率和投资年份,看看不同的值会得什么结果。比如下面展示了1000美元分别在5%和10%收益率的情况下,五年内的增长情况。用户输入为红色字体:

$ awk -f interest1.awk
1000 .05 5
        1050.00
        1102.50
        1157.63
        1215.51
        1276.28
1000 .10 5
        1100.00
        1210.00
        1331.00
        1464.10
        1610.51

For语句

另一个循环语句,for语句,将大部分循环所需的“初始化、条件测试、递增”这三部分压缩到一行里面。当然 for 也是从C语言借来的。可以用 for 来重写上面while的例子:

# interest2 - compute compound interest
#   input:  amount  rate  years
#   output: compounded value at the end of each year

{   for (i = 1; i <= $3; i++)
        printf("\t%.2f\n", $1 * (1 + $2) ^ i)
}

初始化部分即 i = 1只会执行一次。接下来是测试 i <= $3 这个条件;如果为真,则执行主体部分,即单条printf语句。主体之后再执行 i++ 递增,而循环的下一个迭代继续从条件测试开始。(条件——主体——递增)。这个代码更加紧凑,而且由于主体只有单条语句,可以不加大括号。

如果要做N次循环,从1到N(包含N),上面例子里给出的是标准用法。如果你自己写for循环语句时,发现初始化和结束条件和这个不太一样(i=1;i<=n;++i),建议再多看两眼,防止出错。

FizzBuzz

学会了条件和循环,下面来写一个有趣的程序FizzBuzz。FizzBuzz有时用来检查一个求职者是否根本不会写程序。任务很简单,就是把1到100的数字打印出来,但如果数字能被3整除,则打印fizz,如果能被5整除,则打印buzz,若都能整除,则打印fizzbuzz。

这个程序使用了取模或者说求余运算符 % 

awk '
BEGIN {
  for (i = 1; i <= 100; i++) {
    if (i%15 == 0)  # divisible by both 3 and 5
      print i, "fizzbuzz"
    else if (i%5 == 0)
      print i, "buzz"
    else if (i%3 == 0)
      print i, "fizz"
    else
      print i
  }
} '

所有事情都在BEGIN里面干了,任何文件名参数都会被忽略。注意 else if 的缩进都是一样的,表明这是同一序列的决策分支。

1.7 数组

Awk提供了数组,用来保存一组相关的值。下面这个程序会把输入的行按行号倒序输出。

# reverse - print input in reverse order by line

    { line[NR] = $0 }  # remember each input line

END { i = NR           # print lines in reverse order
      while (i > 0) {
          print line[i]
          i--
      }
    }

第一个动作将输入行逐一保存到数组 line 中,第一行保存在line[1],第二行保存在line[2],以此类推。END 动作使用while循环把数组内容倒序输出。

用emp.data做输入,输出是

Susie   17      18
Mary    22.50   22
Mark    25      20
Kathy   15.50   10
Dan     19      0
Beth    21      0

可以用 for 语句来重写这个程序:

# reverse - print input in reverse order by line (version 2)

    { line[NR] = $0 }  # remember each input line

END { for (i = NR; i > 0; i--)
          print line[i]
    }

这个例子里面的数组下标是数值,但Awk最有用的一个特性就是,数组下标并不局限于数值,它可以是字符串。后续章节会有样例。

你可能感兴趣的:(AWK,linux,开发语言)