Blog

FIELDWIDTHS变量

Content #

FIELDWIDTHS变量可以不通过字段分隔符读取记录。有些应用程序并没有使用字段分隔符,而是将数据放置在记录中的特定列。在这种情况下,必须设定 FIELDWIDTHS变量来匹配数据在记录中的位置。

一旦设置了FIELDWIDTHS变量,gawk就会忽略FS变量,并根据提供的字段宽度来计算字段。下面这个例子采用的是字段宽度而非字段分隔符: $ cat data1b 1005.3247596.37 115-2.349194.00 05810.1298100.1 $ gawk ‘BEGIN{FIELDWIDTHS=“3 5 2 5”}{print $1,$2,$3,$4}’ data1b 100 5.324 75 96.37 115 -2.34 91 94.00 058 10.12 98 100.1 $ FIELDWIDTHS变量定义了4个数据字段,gawk依此解析记录。每个记录中的数字串会根据已定义好的字段宽度来分割。

警告:一定要记住,一旦设定了FIELDWIDTHS变量的值,就不能再改动了。这种方法并不适用于变长的数据字段。

From #

Linux命令行与shell脚本编程大全

zsh shell的独有特性

Content #

zsh shell是由Paul Falstad开发的开源Unix shell。它汲取了所有现存shell的设计理念,增加了许多独有的特性,是为程序员而设计的一款无所不能的高级shell。

下面是zsh shell的一些独有特性。·改进的shell选项处理。·shell兼容性模式。·可加载模块。

可加载模块是shell设计中最先进的特性。你在bash和dash shell中已经看到过,每种shell都包含一组内建命令,这些命令无须借助外部程序即可使用。内建命令的好处在于执行速度快。shell不必在运行命令前先加载一个外部程序,因为内建命令已经在内存中了,随时可用。

zsh shell提供了一组核心内建命令,并具备增添附加命令模块的能力。每个命令模块都为特定场景提供了一组内建命令,比如网络支持和高级数学功能。可以只添加你认为有用的模块。

这项特性提供了一种极佳的方式:既可以在需要较小的shell体积和较少的命令时限制zsh shell的大小,也可以在需要更快的执行速度时增加可用的内建命令数量。

From #

Linux命令行与shell脚本编程大全

计算球队成绩的总分和平均分(awk)

Content #

假设我们手边有一个数据文件,其中包含了两支队伍(每队两名选手)的保龄球比赛得分情况: $ cat scores.txt Rich Blum,team1,100,115,95 Barbara Blum,team1,110,115,100 Christine Bresnahan,team2,120,115,118 Tim Bresnahan,team2,125,112,116 $ 每位选手各有3场比赛的成绩,这些成绩都保存在数据文件中。每位选手由第二列的队名来标识。下面的shell脚本会计算每队总分和平均分:

$ cat bowling.sh
#!/bin/bash

for team in $(gawk -F, '{print $2}' scores.txt | uniq)
do
   gawk -v team=$team 'BEGIN{FS=","; total=0}
   {
      if ($2==team)
      {
          total += $3 + $4 + $5;
      }
   }
   END {
      avg = total / 6;
      print "Total for", team, "is", total, ",the average is",avg
   }' scores.txt
done
$

for循环中的第一条gawk语句会过滤出数据文件中的队名,然后使用uniq命令返回不重复的队名。for循环会再对每个队进行迭代。

...

创建函数库(awk)

Content #

gawk提供了一种方式以将多个函数放入单个库文件中,这样就可以在所有的gawk 脚本中使用了。

首先,需要创建一个包含所有gawk函数的文件: $ cat funclib function myprint() { printf “%-16s - %s\n”, $1, $4 } function myrand(limit) { return int(limit * rand()) } function printthird() { print $3 } $ funclib文件含有3个函数定义。加上-f命令行选项就可以使用该文件了。很遗憾,-f选项不能和内联gawk脚本(inline gawk script)一起使用,不过可以在同一命令行中使用多个-f选项。

因此,要使用库,只要创建好gawk脚本文件,然后在命令行中同时指定库文件和脚本文件即可: $ cat script4 BEGIN{ FS="\n"; RS=""} { myprint() } $ gawk -f funclib -f script4 data2 Ima Test - (312)555-1234 Frank Tester - (317)555-9876 Haley Example - (313)555-4938 $

From #

Linux命令行与shell脚本编程大全

...

使用自定义函数(awk)

Content #

在定义函数时,它必须出现在所有代码块之前(包括BEGIN代码块)。这有助于将函数代码与gawk脚本的其他部分分开: $ gawk ' > function myprint() > { > printf “%-16s - %s\n”, $1, $4 > } > BEGIN{FS="\n"; RS=""} > { > myprint() > }’ data2 Ima Test - (312)555-1234 Frank Tester - (317)555-9876 Haley Example - (313)555-4938 $ 脚本中定义了myprint()函数,该函数负责格式化记录中的第一个和第四个数据字段以供打印输出。然后,gawk脚本会调用该函数以显示数据文件中的数据。

From #

Linux命令行与shell脚本编程大全

匹配操作符~(awk)

Content #

匹配操作符(~)能将正则表达式限制在记录的特定数据字段。你可以指定匹配操作符、数据字段变量以及要匹配的正则表达式:

$1 ~ /^data/

$1变量代表记录中的第一个数据字段。该表达式会过滤出第一个数据字段以文本 data开头的所有记录。下面例子演示了在gawk脚本中使用匹配操作符的情况: $ gawk ‘BEGIN{FS=","} $2 ~ /^data2/{print $0}’ data1 data21,data22,data23,data24,data25 $ 匹配操作符使用正则表达式/^data2/来比较第二个数据字段,该正则表达式指明这个数据字段要以文本data2开头。这可是个强大的工具,gawk脚本中经常用它在文件中搜索特定的数据元素: $ gawk -F: ‘$1 ~ /rich/{print $1,$NF}’ /etc/passwd rich /bin/bash $ 这个例子会在第一个数据字段中查找文本rich。如果匹配该模式,则打印该记录的第一个数据字段和最后一个数据字段。

也可以用!符号来排除正则表达式的匹配: $1 !~ expression 如果在记录中没有找到匹配正则表达式的文本,就对该记录执行脚本: $ gawk -F: ‘$1 !~ /rich/{print $1,$NF}’ /etc/passwd root /bin/bash daemon /bin/nologin bin /bin/nologin sys /bin/nologin — output truncated — $ 在这个例子中,gawk脚本会打印/etc/passwd文件中用户名不是rich的那些用户名和登录shell。

From #

Linux命令行与shell脚本编程大全

删除数组变量(awk)

Content #

从关联数组中删除数组元素要使用一个特殊的命令: delete array[index] delete命令会从关联数组中删除索引值及其相关的数组元素值: $ gawk ‘BEGIN{ > var[“a”] = 1 > var[“g”] = 2 > for (test in var) > { > print “Index:",test,” - Value:",var[test] > } > delete var[“g”] > print “—” > for (test in var) > print “Index:",test,” - Value:",var[test] > }’ Index: a - Value: 1 Index: g - Value: 2 #

Index: a - Value: 1 $ 一旦从关联数组中删除索引值,就不能再用它来提取数组元素值了。

From #

Linux命令行与shell脚本编程大全

...

遍历数组变量(awk)

Content #

与使用连续数字作为索引的数字型数组不同,关联数组的索引可以是任何内容。如果要在gawk脚本中遍历关联数组,可以用for语句的一种特殊形式: for (var in array) { statements } 这个for语句会在每次循环时将关联数组array的下一个索引赋给变量var,然后执行一遍statements。重要的是要记住这个变量中存储的是索引而不是数组元素值。可以将这个变量用作数组索引,轻松地取出数组元素值: $ gawk ‘BEGIN{ > var[“a”] = 1 > var[“g”] = 2 > var[“m”] = 3 > var[“u”] = 4 > for (test in var) > { > print “Index:",test,” - Value:",var[test] > } > }’ Index: u - Value: 4 Index: m - Value: 3 Index: a - Value: 1 Index: g - Value: 2 $ 注意,索引值没有特定的返回顺序,但它们都能够指向对应的数组元素值。明白这点很重要,因为你不能指望返回值有固定的顺序,只能保证索引值和数据值是对应的。

From #

Linux命令行与shell脚本编程大全

...

定义数组变量(awk)

Content #

可以用标准赋值语句来定义数组变量。数组变量赋值的格式如下:

var[index] = element

其中,var是变量名,index是关联数组的索引值,element是数组元素值。下面是gawk中数组变量的一些示例: capital[“Illinois”] = “Springfield” capital[“Indiana”] = “Indianapolis” capital[“Ohio”] = “Columbus”

From #

Linux命令行与shell脚本编程大全

在命令行中给变量赋值

Content #

可以通过gawk命令行来为脚本中的变量赋值。这允许你在正常的代码之外赋值,即时修改变量值。下面的例子使用命令行变量来显示文件中特定的数据字段: $ cat script1 BEGIN{FS=","} {print $n} $ gawk -f script1 n=2 data1 data12 data22 data32 $ gawk -f script1 n=3 data1 data13 data23 data33 $ 这个特性可以让你在不修改脚本代码的情况下就改变脚本的行为。第一个例子显示了文件的第二个字段,而第二个例子显示了第三个字段,这只需在命令行中设置变量n的值即可。

使用命令行参数来定义变量值会产生一个问题:在设置过变量之后,这个值在脚本的BEGIN部分不可用。 $ cat script2 BEGIN{print “The starting value is”,n; FS=","} {print $n} $ gawk -f script2 n=3 data1 The starting value is data13 data23 data33 $ 可以用-v选项来解决这个问题,它允许在BEGIN部分之前设定变量。在命令行中,-v选项必须放在脚本代码之前: $ gawk -v n=3 -f script2 data1 The starting value is 3 data13 data23 data33 $ 现在,BEGIN部分中的变量n的值就已经是命令行中设定的那个值了。

...