您的位置:首页 > 其它

【awk】1-awk基础篇(又名UNIX.She…

2014-05-08 09:38 204 查看
转自:http://bkeep.blog.163.com/blog/static/1234142902010425110453/

导读:[/b]
1,awk基本语法
2,比较操作符
3,复合表达式
4,next命令
5,变量及变量赋值
6,awk中的赋值操作符
7,BEGIN和END
8,内置变量
9,awk使用shell变量

10,awk中的三种流控制语句
10.1 if语句
10.2 while语句:
10.3 for语句:
11,实验:
12,shell里的特殊变量

正文:[/b]

1,awk基本语法

awk ‘script’ files

script
由下面的结构组成 /pattern/{actions}


例子:打印fruit_prices.txt
文件的内容
[root@master
bkeep]# awk '{print;}' fruit_prices.txt
fruit
price/lbs
quantity
banana
$0.89
100
peach
$0.79
65
kiwi
$1.50
22
pineapple
$1.29
35
apple
$0.99
78

TIPS:[/b]留意printf[/b]的用法
[/b]如果加“-[/b]”说明是左对齐![/b]

[root@master
bkeep]# awk '{printf "%-15s[/b] %s\n", $1, $3;}'
fruit_prices.txt
fruit
quantity
banana
100
peach
65
kiwi
22
pineapple
35
apple
78

留意printf[/b]的用法
[/b]如果不加“-[/b]”说明是右对齐![/b]
[root@master
bkeep]# awk '{printf "s[/b] %s\n", $1, $3;}'
fruit_prices.txt

fruit quantity

banana 100

peach 65

kiwi 22

pineapple 35

apple 78


例子:给价格高于1
美元的水果加个星号
[root@master
bkeep]# cat fruit_prices.txt
fruit
price/lbs
quantity
banana
$0.89
100
peach
$0.79
65
kiwi
$1.50
22
pineapple
$1.29
35
apple
$0.99
78
[root@master
bkeep]# cat price.sh
#!/bin/bash
awk '
/
*\$[1-9][0-9]*\.[0-9][0-9] */ {print $1,$2,$3,"*";} //[/b]星号前面一定要留空格,否则匹配不到[/b]
/
*\$0\.[0-9][0-9] */ {print;}

//[/b]以后养成习惯,/ key /[/b]斜杠和key[/b]之间始终留空格[/b]
'
fruit_prices.txt

执行结果:
[root@master
bkeep]# ./price.sh
banana
$0.89
100
peach
$0.79
65
kiwi $1.50 22
*
pineapple $1.29 35
*
apple
$0.99
78


上面的格式很不好看,我们改改它吧!


TIPS[/b]:[/b]$0[/b]:[/b]awk[/b]使用变量[/b]0[/b]原原本本地存储它所读入的整个输入行。这样可以保持和原来文本格式相同的输出[/b]
[root@master
bkeep]# cat price.sh
#!/bin/bash
awk '
/
*\$[1-9][0-9]*\.[0-9][0-9] */ {print $0[/b],"*";}
/
*\$0\.[0-9][0-9] */ {print;}
'
fruit_prices.txt
[root@master
bkeep]# ./price.sh
banana
$0.89
100
peach
$0.79
65
kiwi
$1.50
22 *
pineapple
$1.29
35 *
apple
$0.99
78

2,比较操作符

语法:expression
{actions;}

expression[/b]
可以使用以下操作符构成[/b]

< [/b]

小于[/b]

> [/b]

大于[/b]

<= [/b]

小于等于[/b]

>= [/b]

大于等于[/b]

== [/b]

等于[/b]

!= [/b]

不等于[/b]

value ~ /pattern/ [/b]

若value[/b]匹配pattern[/b]则为真[/b]

value !~ /pattern/ [/b]

若value[/b]不匹配pattern[/b]则为真[/b]

说明:$2 ~ /^\$[1-9][0-9]* [/b]
将匹配第二列以$[/b]开头,然后大于1[/b]的二位数。(注意,这里是1[/b]而不是10[/b])[/b]


例子:给数量大于50
的水果加星号
[root@master
bkeep]# cat larger.sh
#!/bin/bash
awk '

$3>50[/b]
{printf "%s\t%s\n",
$0,"*"}[/b]

$3<=50 {printf "%s\n",$0}
'
fruit_prices.txt
[root@master
bkeep]# ./larger.sh
fruit
price/lbs
quantity
*[/b]
banana
$0.89
100
*
peach
$0.79
65
*
kiwi
$1.50
22
pineapple
$1.29
35
apple
$0.99
78
*

3,复合表达式

语法:(compound
expression)

(expr1)&&
(expr2)
-------


(expr1)|| (expr2) -------



说明一下:符合表达式必须用括号括起来[/b]

当使用&&[/b]时,expr1[/b]和expr2[/b]必须同时为零(零代表真!呵呵~),复合表达式才为真;[/b]

当使用 ||[/b]

时,expr1[/b]和expr2[/b]
只要有一个为真,复合表达式则为真![/b]


例子:显示价格高于1
美元且数量少于50的水果记录,给打个标记!
[root@master
bkeep]# cat larger.sh
#!/bin/bash
awk '
($2 ~
/^\$[1-9][0-9]*\.[/b][0-9][0-9]$/)
&& ($3<50)
{
//这是一个模式匹配(请参阅比较操作符
printf
"%s\t%s\t%s\n", $0,"*","reorder";
}
'
fruit_prices.txt
[root@master
bkeep]# ./larger.sh
kiwi
$1.50
22
*
reorder
pineapple
$1.29
35
*
reorder

4,next命令


例子:给库存少于50
的水果价格标签!
[root@master
bkeep]# cat next.sh
#!/bin/bash
awk '
$3
<= 50 { printf "%s\t%s\n",$0,"REORDER" ;
}
$3
> 50 {print $0; }
'
fruit_prices.txt

当输入行为:kiwi
$1.50
22

脚本执行以下过程:
1)检查是否第三列的值22小于50,由于值小于50,执行脚本的第二步
2)打印该行,并在行尾添加REORDER标志
3)检查是否第三列的值22大于50,由于值不大于50,脚本读下一行

呵呵,傻子都看得出这种情况下执行第三步是多余的。那么如何跳过呢?可以使用next命令。
next[/b]命令:告诉awk[/b]跳过剩下的所有模式和表达式,并读取输入的下一行,同时从第一个模式或表达式开始处理该行![/b]

修改后的脚本,加入了next[/b]命令![/b]
[root@master
bkeep]# cat next.sh
#!/bin/bash
awk '
$3
<= 50 { printf "%s\t%s\n",$0,"REORDER" ;next;[/b] }
$3
> 50 {print $0; }
'
fruit_prices.txt
[root@master
bkeep]# ./next.sh
fruit
price/lbs
quantity
banana
$0.89
100
peach
$0.79
65
kiwi
$1.50
22
REORDER
pineapple
$1.29
35
REORDER
apple
$0.99
78

现在脚本执行如下;
1)检查是否第三列的值22小于50,由于值小于50,所以执行脚本第二步
2)打印输出行并在该行后打印REORDER标志(有了[/b]next[/b]后就不再执行$3 > 50 {print $0;
}[/b])
3)读取下一输入行并从第一种模式开始

5,变量及变量赋值

下面给变量赋值

fruit=100
//把数字赋给fruit变量

fruit=”peach” //把字符串赋给fruit变量

fruit=$1
//把第一列赋给fruit变量

awk[/b]中的数字操作符:[/b]

+ [/b]

加[/b]

- [/b]

减[/b]

* [/b]

乘[/b]

/ [/b]

除[/b]

% [/b]

求余[/b]

^ [/b]

求幂[/b]


应用例子:统计文件中的空行数

[root@master
bkeep]# cat for.sh
#!/bin/bash
for i in
$@;
//这里我们不知道有多少个文件需要统计,所以用$@来接收参数!
do
if
[ -f $i ]; then

echo $i

awk ' /^$/ { x=x+1;} END{print x;}' $i

else

echo "ERROR:$i not a file."
>&2

fi
done
[root@master
bkeep]# ./for.sh aa bb
aa
//文件名为aa
7
//空行数7
bb
//文件名为bb
4
//空行数为4

6,awk中的赋值操作符

+=
x+=1
就是x=x+1

-=
x-=1
就是x=x-1

*=
x*=1
就是x=x*1

/=
x/=1
就是x=x/1

%=
x%=2
就是x=x%2

^=
x^=2
就是x=x^2

7,BEGIN和END

awk的语法:/pattern/ {action}
pattern:模式

这里pattern有两个特殊模式BEGIN和END

下面是BEGIN
END的语法:

awk ‘
BEGIN { actions
}
/ pattern / {
actions }
/ pattern / {
actions }
END { actions
}
‘ files

BEGIN和END都是可选的

·当指定BEGIN模式时,awk在读取任何输入前执行动作
actions

·当指定END模式时,awk在其退出前执行动作actions

这里要特别注意:比如awk读入aa.txt。那么BEGIN只在读入aa时执行一次,然后按行处理的时候不再执行BEGIN指定的action!(也可以这么理解:BEGIN只对文件生效,而不是按行生效!!);理解了BEGIN,END还会糊涂吗?呵呵!

8,内置变量

gawk语言中有几个十分有用的内置变量,现在列于下面:
NR[/b]
已经读取过的记录数。[/b]
FNR[/b]
从当前文件中读出的记录数。[/b]
FILENAME[/b]
输入文件的名字。[/b]
FS[/b]
字段分隔符(缺省为空格)。[/b]
RS[/b]
记录分隔符(缺省为换行)。[/b]
OFMT[/b]
数字的输出格式(缺省为[/b]% g[/b])。[/b]
OFS[/b]
输出字段分隔符。[/b]
ORS[/b]
输出记录分隔符。[/b]
NF[/b]
当前记录中的字段数。[/b]

如果你只处理一个文件,则NR
和FNR
的值是一样的。但如果是多个文件, NR是对所有的文件来说的,而FNR
则只是针对当前文件而言。

例子:统计空行的脚本:[/b]
[root@master
bkeep]# cat for.sh
#!/bin/bash
for i in
$@;
do
if
[ -f $i ]; then
#
echo $i

awk 'BEGIN { printf "%s\t",FILENAME;} //输出文件名

/^$/ { x+=1;}

//统计空行

END{avg=100*(x/NR); printf "%s\t%3.1f\n",x,avg;}' $i //最后算百分比及打印结果

else

echo "ERROR:$i not a file."
>&2

fi
done
[root@master
bkeep]# ./for.sh aa bb //显示出来的结果很漂亮。可惜了,文件名没出来!

7
87.5
//怀疑FILENAME内置变量被修改了???

4
57.1

9,awk使用shell变量

经过前面的学习,我们知道shell变量的引用由$xxx
实现,而awk中的变量直接使用xxx来引用。所以我们就要思考如何让awk使用shell变量

语法:[/b]

awk ‘script’
awkvar1=value awkvar2=value
......
files[/b]

说明: awk[/b]:[/b]

命令;[/b]
‘script[/b]’:awk[/b]将要执行的脚本;
awkvarN[/b]:awk[/b]的变量;value[/b]:shell[/b]中的变量值;
files[/b]:将要处理的文件名[/b]

【重点实验—[/b]记忆】[/b]


例子:根据用户提供的水果数量,将低于这个值的水果打印出来!

[root@master
bkeep]# cat awk_var.sh
#!/bin/bash
NUM_FRUIT="$1"
//将用户输入传递给shell变量NUM_FRUIT
if [ -z
"$NUM_FRUIT" ]; then NUM_FRUIT=75;fi //如果用户没有输入,则赋默认值75
awk '

$3 <= num_fruit {print;}
//最终将用户输入传递给awk变量num_fruit
' num_fruit="$NUM_FRUIT"[/b]
fruit_prices.txt
//通过此方法将$NUM_FRUIT
//赋值给num_fruit;即把shell变量赋给awk

执行结果:[/b]
[root@master
bkeep]# ./awk_var.sh 40
//将数量低于40的水果打印出来
kiwi
$1.50
22
pineapple
$1.29
35
[root@master
bkeep]# ./awk_var.sh 30
//将数量低于30的水果打印出来
kiwi
$1.50
22

10,awk中的三种流控制语句

if语句

while语句

for语句

10.1 if语句

if (expression1)
{action1}

else if (expression2)
{action2}

else { action3}

执行过程:[/b]

1)计算expression1的值

2)若expression1为真,执行action1并推出if语句

3)若expression1为假,计算expression2

4)若expression2为真,执行action2并退出if语句

5)若expression2为假,执行action3并退出if


举例:若水果价格高于1
美元,那么给它加星号;若水果数量少于50,则给它加REORDER
[root@master
bkeep]# cat reorder.sh
#!/bin/bash
awk '{

printf "%s\t",$0;
if
( $2 ~ /\$[1-9][0-9]*\.[0-9][0-9]/ ) {

printf " * ";

if ($3 <= 75) {

printf "REORDER\n";

} else {

printf "\n";

}

}else {

if ($3<=75) {

printf "REORDER\n";

}else {

printf "\n";

}

}
}'
fruit_prices.txt

执行结果:[/b]
[root@master
bkeep]# ./reorder.sh
fruit
price/lbs
quantity
banana
$0.89
100
peach
$0.79
65
REORDER
kiwi
$1.50
22
* REORDER
pineapple
$1.29
35
* REORDER
apple
$0.99
78

10.2 while语句:

while (expression) { actions
}

若expression为真,则执行actions
[root@master
bkeep]# awk 'BEGIN { x=0;while(x<3) {x+=1;[/b]print x;}}' //先给x+1再输出
1
2
3
[root@master
bkeep]# awk 'BEGIN { x=0;while(x<3) {print
x;x++[/b]}}'
//先输出再给x+1
0
1
2

Tips[/b]:do[/b]语句是while[/b]语句衍生出来的;区别在于do[/b]至少执行一次,while[/b]有可能不执行[/b]

10.3 for语句:

for
(initialize_counter;
test_counter;increment_counter)
{

action

}

解释一下,呵呵

for (初始化计数器变量;测试计数器是否到顶了;增加计数器的值) {

要执行的动作!

}


【常用】例子:循环迭代处理记录中的域并输出他们

[root@master
bkeep]# cat for2.sh
#!/bin/bash
awk '{

for (x=1;x<=NF;x+=1) {

printf "%s
",$x "zbb";

}

printf "\n";
}'
fruit_prices.txt

[root@master
bkeep]# ./for2.sh
fruitzbb
price/lbszbb
quantityzbb
bananazbb
$0.89zbb
100zbb
peachzbb
$0.79zbb
65zbb

根据输出我们重点理解下awk中for循环的执行过程
1)读取一行数据
2)执行for循环,处理每一个字段,将其输出,退出for循环
3)执行第二个action即输出一个换行符
4)重复1~3,直到处理完所有行!

11,实验:


例子:倒序显示记录中的每个行


方法一:用for[/b]实现[/b]
#!/bin/bash
awk '
{a[NR]=$0};
//第一个action:把记录存储在一个数组里面
END{for
(x=NR;x>0;x-=1) {
//第二个action:for循环,x=NR总行数

printf "%s\n",a[x];
//如果x>0,则x=x-1,倒序输出a[x]数组中的内容!

}
}'
fruit_prices.txt //要处理的文件名!

方法2[/b]:用while[/b]实现[/b]
#!/bin/bash
awk '
{line[NR] = $0 }
//把所有记录都存放到数组里面
END {var=NR

//把总行数赋给变量var
while (var
> 0){ //当var大于0时,执行后面的action
print
line[var]
var--
//var=var-1
}}
'
fruit_prices.txt
//文件名

执行结果:[/b]
[root@master
bkeep]# ./re.sh
apple
$0.99
78
pineapple
$1.29
35
kiwi
$1.50
22
peach
$0.79
65
banana
$0.89
100
fruit
price/lbs
quantity

12,shell里的特殊变量

# sh
/usr/local/bkeep/shell.sh 001 002
I'm $0
is:/usr/local/bkeep/shell.sh
//正在被执行脚本的名字;`basename $0`
I'm $1
is:001
//$1接收到的参数
I'm $2
is:002
//$2接收到的参数
I'm $#
is:2
//总共接收到的参数个数
I'm $* is:001
002
//把接收到的参数全部打印出来
I'm $@ is:001
002
//同上
I'm $?
is:0
//上一个脚本的退出状态“0”代表正常;“1”非正常退出
I'm $$
is:24137
//当前执行脚本的进程ID
I'm $!
is:
//前一个后台[/b]进程的id


例子:再进一步解释下$*
和$@吧;仔细看下面的例子,我就不废话了!
[root@master
bkeep]# cat shell.sh
#!/bin/bash
cc=$*
echo "I'm \$1
is:$1"
echo "I'm \$2
is:$2"
echo "I'm \$*
is:$*"
echo "I'm \$4
is:$4"
[root@master
bkeep]# ./shell.sh 11 22 33 "44" 55
I'm $1
is:11
I'm $2
is:22
I'm $* is:11 22 33
44 55
I'm $4
is:44


应用例子:统计文件中的空行数

[root@master
bkeep]# cat for.sh
#!/bin/bash
for i in
$@;
//这里我们不知道有多少个文件需要统计,所以用$@来接收参数!
do
if
[ -f $i ]; then

echo $i

awk ' /^$/ { x=x+1;} END{print x;}' $i

else

echo "ERROR:$i not a file."
>&2

fi
done
[root@master
bkeep]# ./for.sh aa bb
aa
//文件名为aa
7
//空行数7
bb
//文件名为bb
4
//空行数为4
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: