awk

awk

标签(空格分隔): shell编程


Awk文本处理

1.进行逐行扫描文件(或流), 从第一行到最后一行
2.寻找匹配的特定模式的行,在行上进行操作
3.如果没有指定处理动作,则把匹配的行显示到标准输出
4.如果没有指定模式,则所有被操作的行都被处理

awk的语法格式

awk [options] 'commands' filenames 
awk [options] -f awk-script-file filenames

选项 options

-F 定义输入字段分隔符,默认的分隔符, 空格或tab键

命令 command

行处理前 行处理 行处理后

BEGIN{}  {}  END{}

Awk 工作原理

1.awk将文件中的每一行作为输入, 并将每一行赋给内部变量$0, 以换行符结束

2.awk开始进行字段分解,每个字段存储在已编号的变量中,从$1开始[默认空格分割]

3.awk默认字段分隔符是由内部FS变量来确定, 可以使用-F修订

4.awk行处理时使用了print函数打印分割后的字段

5.awk在打印后的字段加上空格,因为1,3 之间有一个逗号。逗号被映射至OFS内部变量中,称为输出字段分隔符, OFS默认为空格.

6.awk输出之后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理。该过程将持续到所有行处理完毕.


Awk内部变量

$0保存当前记录的内容

awk '{print $0}' /etc/passwd

NR记录输入总的编号(行号)

awk '{print NR,$0}' /etc/passwd
awk 'NR<=3' /etc/passwd

FNR当前输入文件的编号(行号)

awk '{print NR,$0}' /etc/passwd /etc/hosts
awk '{print FNR,$0}' /etc/passwd /etc/hosts

NR与FNR

vim info1.txt

001,小明
002,小张
003,小王

vim info2.txt

001,男,25
002,女,21
003,男,20

合并两个文件,得到如下结果

001,小明,男,25
002,小张,女,21
003,小王,男,20
awk -F "," 'NR==FNR{s[$1]=$0;next}{print s[$1]","$2","$3}' info1.txt info2.txt
join -t ',' -o 1.1 1.2 2.2 2.3 info1.txt info2.txt

NF保存行的最后一列

awk -F ":" '{print NF,$NF}' /etc/passwd /etc/hosts

FS指定字段分割符, 默认是空格

//以冒号作为字段分隔符

awk -F: '/root/{print $1,$3}' /etc/passwd

awk 'BEGIN{FS=":"} {print $1,$3}' /etc/passwd

//以空格冒号tab作为字段分割

awk -F'[ :\t]' '{print $1,$2,$3}' /etc/passwd

OFS指定输出字段分隔符

//,逗号映射为OFS, 初始情况下OFS变量是空格

awk -F: '/root/{print $1,$2,$3,$4}' /etc/passwd

awk 'BEGIN{FS=":"; OFS="+++"} /^root/{print $1,$2}' /etc/passwd

RS输入记录分隔符,默认为换行符[了解]

awk -F: 'BEGIN{RS=" "} {print $0}' /etc/hosts

ORS将文件以空格为分割每一行合并为一行

awk -F: 'BEGIN{ORS=" "} {print $0}' /etc/hosts

print 输出函数

date|awk '{print $2,"5月份""\n",$NF,"今年"}'

awk -F: '{print "用户是:" $1 "\t 用户uid: " $3  "\t 用户gid:" $4}' /etc/passwd

printf 格式化输出函数

awk -F: '{printf "%-15s %-10s %-15s\n", $1, $2, $3}' /etc/passwd

%s 字符类型
%d 数值类型
占 15 字符

  • 表示左对齐,默认是右对齐
    printf 默认不会在行尾自动换行,加\n

FS与RS

vim record.txt

小明
电话:010-10011010
手机:13388888888

小军
电话:010-10011011
手机:13399999999

将以上文件内容变为如下格式

小明 电话:010-10011010 手机:13388888888
小军 电话:010-10011011 手机:13399999999
awk 'BEGIN{FS="\n";RS=""}{print $1"\t"$2"\t"$3}' record.txt

Awk模式动作

awk语句都由模式和动作组成。
模式部分决定动作语句何时触发及触发事件。
如果省略模式部分,动作将时刻保持执行状态。模式可以是条件语句或复合语句或正则表达式。

1.正则表达式

//匹配记录(整行)

awk '/^root/' /etc/passwd
awk '$0 ~ /^root/' /etc/passwd

//匹配字段:匹配操作符(~ !~)

awk '$1~/^root/' /etc/passwd
awk '$NF !~ /bash$/' /etc/passwd

2.比较表达式

比较表达式采用对文本进行比较,只有当条件为真,才执行指定的动作。
比较表达式使用关系运算符,用于比较数字与字符串

关系运算符

运算符 含义 示例
< 小于 x < y
<= 小于或等于 x<=y
== 等于 x==y
!= 不等于 x!=y
>= 大于等于 x>=y
> 大于 x>y

//uid为0的列出来

awk -F ":" '$3==0' /etc/passwd

//uid小于10的全部列出来

awk -F: '$3 < 10' /etc/passwd

//用户登陆的shell等于/bin/bash

awk -F: '$7 == "/bin/bash" ' /etc/passwd

//第一列为alice的列出来

awk -F: '$1 == "alice" ' /etc/passwd

//为alice的用户列出来

awk -F: '$1 ~ /alice/' /etc/passwd
awk -F: '$1 !~ /alice/' /etc/passwd

//磁盘使用率大于多少则,则打印可用的值

df |awk '/\/$/'|awk '$3>1000000 {print $4}'

3.条件表达式

awk -F: '$3>300 {print $0}' /etc/passwd
awk -F: '{if($3>300) print $0}' /etc/passwd
awk -F: '{if($3>5555){print $3} else {print $1}}' /etc/passwd

4.运算表达式

awk -F: '$3 * 10 > 500000' /etc/passwd

awk -F: 'BEGIN{OFS="--"} { if($3*10>50000) {print $1,$3} } END {print "打印ok"}' /etc/passwd

awk '/southem/{print $5 + 10}' file 
awk '/southem/{print $5 + 1.5}' file
awk '/southem/{print $8 - 8}' file 
awk '/southem/{print $8 / 3 }' file  
awk '/southem/{print $8 * 4 }' file 
awk '/southem/{print $8 % 2 }' file

5.逻辑操作符和复合模式

&&逻辑与 || 逻辑或 !逻辑非

//匹配用户名为root并且打印uid小于15的行

awk -F: '$1~/root/ && $3<=15' /etc/passwd 

//匹配用户名为root或uid大于5000

awk -F: '$1~/root/ || $3>=5000' /etc/passwd

awk示例1

 awk '/west/' file 
 awk '/^north/' file 
 awk '$3 ~ /^north/' file 
 awk '/^(no|so)/' file 
 awk '{print $3,$2}' file
 awk '{print $3 $2}' file 
 awk '{print $0}' file 
 awk '{print "Number of fields: "NF}' file 
 awk '/northeast/{print $3,$2}' file
 awk '/^[ns]/{print $1}' file 
 awk '$5 ~ /\. [7-9]+/' file 
 awk '$2 !~ /E/{print $1,$2}' file 
 awk '$3 ~ /^Joel/{print $3 "is a nice boy."}' file 
 awk '$8 ~ /[0-9][0-9]$/{print $8}' file
 awk '$4 ~ /Chin$/{print "The price is $" $8 "."}' file 
awk '/Tj/{print $0}' file 
awk -F: '{print "Number of fields: "NF}' /etc/passwd 
awk -F"[ :]" '{print NF}' /etc/passwd 

awk条件

if

语句格式:
{ if(表达式){语句;语句;... }}

//打印当前管理员用户名称

awk -F: '{ if($3==0){print $1 "is adminisitrator"} }' /etc/passwd

//统计系统用户数量

awk -F: '{ if($3>0 && $3<1000){i++}} END {print i}' /etc/passwd

//统计普通用户数量

awk -F: '{ if($3>1000){i++}} END {print i}' /etc/passwd

写出一个shell脚本,把当前目录下的文本文件number.txt里面数字大于100的求和并输出,并打印所在行行号及内容,最后还要输出每一行的总和。
[root@m01 ~]# cat number.txt
100
98
205
303
1
99
66
33

awk '{if($1>100){sum+=$1;print NR,$0}}{i+=$1}END{print sum,i}' number.txt 
3 205
4 303
508 905

if...else

语句格式:
{if(表达式){语句;语句;... }else{语句;语句;...}}

awk -F: '{if($3==0){print $1} else {print $7}}' /etc/passwd
awk -F: '{if($3==0) {count++} else{i++} }' /etc/passwd
awk -F: '{if($3==0){count++} else{i++}} END{print " 管理员个数: "count ; print " 系统用户数: "i}' /etc/passwd

if...else if...else

语句格式:
{if(表达式 1){语句;语句;... }else if(表达式 2){语句;语句;. .. }else{语句;语句;... }}

awk -F: '{ if($3==0){i++} else if($3>0 && $3<1000){j++} else if($3>1000) {k++}} END {print i;print j;print k}' /etc/passwd

awk -F: '{ if($3==0){i++} else if($3>0 && $3<1000){j++} else if($3>1000) {k++}} END {print "管理员个数"i; print "系统用户个数" j; print "系统用户个 数" }' /etc/passwd
管理员个数1
系统用户个数29
系统用户个数69

switch-case

BEGIN{
  a=2;
  b=2;
  c=3
  switch(a){
  case 1: print a;break;
  case 2: print b;break;
  case 3: print c;break;
  }
}

awk循环语句

for循环

C格式

for(初值;终值;步长值){语句}

awk 'BEGIN{for(i=1;i<=5;i++){print i} }' 
//将每行打印 10 次
awk -F: '{ for(i=1;i<=10;i++) {print $0} }' passwd

列表

for(变量 in 数组){语句}

while循环

awk 'BEGIN{ i=1; while(i<=10){print i; i++} }'
awk -F: '{i=1; while(i<=NF){print $i; i++}}' /etc/passwd
awk -F: '{i=1; while(i<=10) {print $0; i++}}' /etc/passwd

cat a.txt
111 222
333 444 555
666 777 888 999

awk '{i=1;while(i<=NF){print $i;i++}}' a.txt

用awk获取文件中第三列打到倒数第二列字段

awk.awk
#!/usr/bin/awk
BEGIN{
FS=":"
OFS=":"
}
{
t=$2;
i=2;
while (i<NF-1)
{
  $i=$(i+1);
  i++;
}
$(NF-1)=t;
print $0;
}

运行

awk -f awk.awk /etc/passwd

do-while

do
{语句}
while(条件)

break

当 break 语句用于 while 或 for 语句时,导致退出程序循环

continue

当 continue 语句用于 while 或 for 语句时,使程序循环移动到下一个迭代

next

能够导致读入下一个输入行,并返回到脚本的顶部。这可以避免对当前输入行执行其他的操作过程

vim test.txt

web01[192.168.2.100]
httpd ok 
tomcat ok 
sendmail ok 
web02[192.168.2.101] 
httpd ok 
postfix ok 
web03[192.168.2.102] 
mysqld ok 
httpd ok

转换为如下格式

web01[192.168.2.100]    httpd ok 
web01[192.168.2.100]    tomcat ok 
web01[192.168.2.100]    sendmail ok 
web02[192.168.2.101]    httpd ok 
web02[192.168.2.101]    postfix ok 
web03[192.168.2.102]    mysqld ok 
web03[192.168.2.102]    httpd ok
awk '/^web/{T=$0;next;}{print T"\t"$0;}' test.txt 

vim test1.txt

web01[192.168.2.100]    httpd ok 
web01[192.168.2.100]    tomcat ok 
web01[192.168.2.100]    sendmail ok 
web02[192.168.2.101]    httpd ok 
web02[192.168.2.101]    postfix ok 
web03[192.168.2.102]    mysqld ok 
web03[192.168.2.102]    httpd ok

转换为如下格式

web01[192.168.2.100]
httpd ok
tomcat ok
sendmail ok
web02[192.168.2.101]
httpd ok
postfix ok
web03[192.168.2.102]
mysqld ok
httpd ok
awk 't!=$1{t=$1;print $1"\n"$2,$3;next}{print $2,$3}' test1.txt
awk '{if(t!=$1){t=$1;print $1"\n"$2,$3}else{print $2,$3}}' test1.txt

exit

语句使主输入循环退出并将控制转移到END,如果END存在的话。如果没有定义END规则,或在END中应用exit语句,则终止脚本的执行


awk数组

awk -F: '{username[++i]=$1} END{print username[1]}' /etc/passwd
awk -F: '{username[i++]=$1} END{print username[1]}' /etc/passwd
awk -F: '{username[i++]=$1} END{print username[0]}' /etc/passwd

注意:将需要统计的某个字段作为数组的索引,最后对索引进行遍历

按索引遍历

awk -F: '{username[x++]=$1} END{for(i in username) {print i,username[i]} }' /etc/passwd

awk -F: '{username[++x]=$1} END{for(i in username) {print i,username[i]} }' /etc/passwd

1.统计/etc/passwd 中各种类型 shell 的数量

awk -F: '{shells[$NF]++} END{ for(i in shells){print i,shells[i]} }' /etc/passwd

2.网站访问状态统计

ss -an|awk '/:80/{tcp[$2]++} END {for(i in tcp){print i,tcp[i]}}'

3.统计当前访问的每个IP的数量

ss -an|awk -F ':' '/:80/{ips[$(NF-1)]++} END {for(i in ips){print i,ips[i]}}'

Awk数组案例

Nginx日志分析,日志格式如下:

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

52.55.21.59 - - [25/Jan/2018:14:55:36 +0800] "GET /feed/ HTTP/1.1" 404 162 "https://www.google.com/" "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; de) Presto/2.9.168 Version/11.52" "-"

1.统计2015年11月22日,当天的PV量

grep "22/Nov/2015" access.log |wc -l
awk '/22\/Nov\/2015/{i++}END{print i}' access.log

//统计15-19点的pv量

awk '$4>="[25/Jan/2018:15:00:00" && $4<="[25/Jan/2018:19:00:00 {print $0}"' access.log |wc -l

2.统计2018年01月25日,一天内访问最多的10个IP

awk '/25\/Jan\/2018/ {ips[$1]++} END {for(i in ips){ print ips[i],i}}' access.log |sort -rn|head

//统计15-19点访问次数最多的10个IP

awk '$4>="[25/Jan/2018:15:00:00" && $4<="[25/Jan/2018:19:00:00"' access.log |awk '{ips[$1]++} END {for(i in ips){print ips[i],i}}'|sort -rn|head

3.统计2018年01月25日,访问大于100次的IP

awk '/25\/Jan\/2018/ {ips[$1]++} END {for(i in ips){if(ips[i]>100){print i,ips[i]}}}' access.log

4.统计2018年01月25日,访问最多的10个页面($request top 10)

awk '/25\/Jan\/2018/ {request[$7]++} END {for(i in request){print request[i],i}}' access.log |sort -rn|head

5.统计2018年01月25日,每个URL访问内容总大小($body_bytes_sent)

awk '/25\/Jan\/2018/ {request[$7]++;size[$7]+=$10} END {for(i in request){print request[i],i,size[i]}}' access.log |sort -rn|head

6.统计2018年01月25日,每个IP访问状态码数量($status)

awk '{ip_code[$1 " " $9]++} END {for(i in ip_code){print ip_code[i],i}}' access.log|sort -rn|head

7.统计2018年01月25日,访问状态码为404及出现的次数($status)

grep "404" log.bjstack.log |wc -l
awk '{if($9=="404") code[$9]++} END {for(i in code){print i,code[i]}}' access.log

8.统计2018年01月25日,15:00-19:00访问状态码是404

awk '$4>="[25/Jan/2018:15:00:00" && $4<="[25/Jan/2018:19:00:00" && $9=="404" {code[$9]++} END {for(i in code){print i,code[i]}}' access.log

awk '$9=="404" {code[$9]++} END {for(i in code){print i,code[i]}}' access.log

9.统计2018年01月25日,各种状态码数量

awk '{code[$9]++} END {for(i in code){print i,code[i]}}' access.log

awk 'BEGIN{i=j=k=n=p=0}{if($9>=100 && $9<200) {i++}
else if ($9>=200 && $9<300) {j++}
else if ($9>=300 && $9<400) {k++}
else if ($9>=400 && $9<500) {n++}
else if($9>=500) {p++}}
END{print i,j,k,n,p,i+j+k+n+p}' access.log

awk数组练习

cat a.txt
a  1
b  3
c  2
d  7
b  5
a  3 
g  2
f  6
d  9


awk '{str[$1]+=$2}END{for (i in str){print i,str[i]}}' a.txt 
a 4
b 8
c 2
d 16
f 6
g 2


awk '{if(str[$1]){str[$1]=str[$1]" "$2}else{str[$1]=str[$1]$2}}END{for (i in str){print i,str[i]}}' a.txt 
a 1 3
b 3 5
c 2
d 7 9
f 6
g 2

awk -F '[ ]+' '$7~/(jpg|bmp|png|jpeg|gif)$/{count[$7]++;sum[$7]+=$10}END{for (i in count)print count[i]"次", i,sum[i]}' access.log

三目运算符

迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值

[root@web03 ~]# cat lessons.txt 
634751 预排
568688 预排
386760 删除
619373 预排
428491 预排
487563 完成
603342 完成
436339 完成
结果:
删除  386760
完成  487563,603342,436339
预排  634751,568688,619373,428491

awk '{a[$2]=a[$2]" "$1}END{for(i in a) print i,a[i]}' lessons.txt
删除  386760
完成  487563 603342 436339
预排  634751 568688 619373 428491

awk '{a[$2]=a[$2]","$1}END{for(i in a) print i,a[i]}' lessons.txt
删除 ,386760
完成 ,487563,603342,436339
预排 ,634751,568688,619373,428491

awk '{a[$2]=a[$2]?a[$2]","$1:a[$2]$1}END{for(i in a) print i,a[i]}' lessons.txt
删除 386760
完成 487563,603342,436339
预排 634751,568688,619373,428491

awk '{if(a[$2]){a[$2]=a[$2]","$1}else{a[$2]=a[$2]$1}}END{for(i in a) print i,a[i]}' lessons.txt
删除 386760
完成 487563,603342,436339
预排 634751,568688,619373,428491

awk函数

awk内置函数

gsub

gsub(/正则匹配/,"替换后的内容",字段)

[root@oldboy files]# awk '$2~/^Xiaoyu$/{gsub(/:/,"$",$NF);print $NF}' reg.txt 
$155$90$201
[root@m01 ~]# cat test 
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin

[root@m01 ~]# awk '{gsub("root","wuxing");print > "test"}' test
[root@m01 ~]# cat test 
wuxing:x:0:0:wuxing:/wuxing:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/wuxing:/sbin/nologin

substr

substr(某一列,从第几个字符开始,截取几个字符结束)

echo abcdefghi |awk '{print substr($1,6,2)}'
fg

每分钟每个资源的访问次数最多的10个

awk '{a[substr($4,2,17)" "$7]++}END{for (i in a) print a[i],i}' access.log |sort -rn |head
151 22/Nov/2015:11:37 /online/api/mc/cart/new/getCart.json
117 22/Nov/2015:11:29 /online/api/mc/cart/new/getCart.json
116 22/Nov/2015:11:38 /online/api/mc/cart/new/getCart.json
110 22/Nov/2015:11:38 /online/api/mc/sys/nowTime.json
109 22/Nov/2015:11:34 /online/api/mc/cart/new/getCart.json
108 22/Nov/2015:11:30 /online/api/mc/cart/new/getCart.json
104 22/Nov/2015:12:00 /online/api/mc/sys/nowTime.json
104 22/Nov/2015:11:36 /online/api/mc/cart/new/getCart.json
104 22/Nov/2015:11:27 /online/api/mc/sys/nowTime.json
103 22/Nov/2015:11:30 /online/api/mc/sys/nowTime.json

split

精确切割
split(s, a [, r])
split(某一列,数组名字,/正则表达式/)
把某一列通过正则表达式切割,切完后放到数组中

  • 注意:数组元素是从1开始
echo GET /mobile/theme/oldboy/common/images/arrow-down2.png
GET /mobile/theme/oldboy/common/images/arrow-down2.png

echo GET /mobile/theme/oldboy/common/images/arrow-down2.png |awk '{split($2,arr,/\./);print arr[1]}'
/mobile/theme/oldboy/common/images/arrow-down2

echo GET /mobile/theme/oldboy/common/images/arrow-down2.png |awk '{split($2,arr,/\./);print arr[2]}'
png

echo GET /mobile/theme/oldboy/common/images/arrow-down2.png |awk '{split($2,arr,/\./);print arr[1],arr[2]}'
/mobile/theme/oldboy/common/images/arrow-down2 png

echo GET /mobile/theme/oldboy/common/images/arrow-down2.png |awk '{split($2,arr,/\./);for(i in arr) print i}'
1
2

echo GET /mobile/theme/oldboy/common/images/arrow-down2.png |awk '{split($2,arr,/\./);for(i in arr) print i,arr[i]}'
1 /mobile/theme/oldboy/common/images/arrow-down2
2 png

system

awk调用shell命令

awk 'BEGIN{system("ls")}'

awk自定义函数

awkfun.awk

#!/usr/bin/awk
function sum(num1,num2)
{
  s=num1+num2;
  print s;
}

BEGIN{
  sum(1,2)
}
#!/usr/bin/awk
function sum(num1,num2)
{
  s=num1+num2;
  return s;
}

BEGIN{
  res=sum(1,2);
  print res;
}

运行awk脚本

awk -f awkfun.awk

awk命令行参数

ARGC是命令行参数数量
ARGV是将命令行参数存到数组,元素由ARGC指定,数组下标从0开始

awk 'BEGIN{print ARGC}' 1 2 3 
4 

awk 'BEGIN{print ARGV[0]}' 
awk 

awk 'BEGIN{print ARGV[1]}' 1 2 
1

蓄水池问题

某蓄水池有甲,丙两条进水管和乙,丁两条排水管,要灌满一池水,单开甲需要3个小时,单开丙管需要5小时,要排光一池水,单开乙管需要4小时,单开丁管需要6小时,现在池内有1/6池水,如果按照甲乙丙丁的顺序,循环开各水管,每次每管开一小时。问多少时间后水池开始溢出水?

shell脚本

#!/bin/bash
s=10
t=0
va=$(printf "%.2f" `echo "scale=2;60/180" |bc`)
vb=$(printf "%.2f" `echo "scale=2;60/240" |bc`)
vc=$(printf "%.2f" `echo "scale=2;60/300" |bc`)
vd=$(printf "%.2f" `echo "scale=2;60/360" |bc`)
while (($(echo "$s<60" |bc)==1));do
  if (($(echo "$s<60" |bc)==1));then
    for ((i=1;i<=60;i++));do
      s=$(printf "%.2f" `echo "scale=2;$s+$va" |bc`)
      ((t++))
      if (($(echo "$s<60" |bc)!=1));then
        break
      fi
    done
  fi

  if (($(echo "$s<60" |bc)==1));then
    s=$(printf "%.2f" `echo "scale=2;$s-$vb*60" |bc`)
    ((t+=60))
  fi   

  if (($(echo "$s<60" |bc)==1));then
    for ((i=1;i<=60;i++));do
      s=$(printf "%.2f" `echo "scale=2;$s+$vc" |bc`)
      ((t++))
      if (($(echo "$s<60" |bc)!=1));then
        break
      fi

    done
  fi

  if (($(echo "$s<60" |bc)==1));then
    s=$(printf "%.2f" `echo "scale=2;$s-$vd*60" |bc`)
    ((t+=60))
  fi 
  
done
echo $t
#!/bin/bash
s=10
t=0
va=$(printf "%.2f" `echo "scale=2;60/180" |bc`)
vb=$(printf "%.2f" `echo "scale=2;60/240" |bc`)
vc=$(printf "%.2f" `echo "scale=2;60/300" |bc`)
vd=$(printf "%.2f" `echo "scale=2;60/360" |bc`)

function s_add(){
  vx=$1
  if (($(echo "$s<60" |bc)==1));then
    for ((i=1;i<=60;i++));do
      s=$(printf "%.2f" `echo "scale=2;$s+$vx" |bc`)
      ((t++))
      if (($(echo "$s<60" |bc)!=1));then
        break
      fi
    done
  fi

}

function s_dec(){
  vx=$1
  if (($(echo "$s<60" |bc)==1));then
    s=$(printf "%.2f" `echo "scale=2;$s-$vx*60" |bc`)
    ((t+=60))
  fi

}

while (($(echo "$s<60" |bc)==1));do
  s_add $va
  s_dec $vb 
  s_add $vc
  s_dec $vd 
 
done
echo $t

awk脚本

#!/usr/bin/awk
BEGIN{
s=10;
va=60/180;
vb=60/240;
vc=60/300;
vd=60/360;
while(s<60)
{
  if(s<60)
  {
    for(i=1;i<=60;i++)
    {
      s+=va;
      t+=1;
      if(s>=60)
      {
        break;
      }
    }
  }

    if(s<60)
    {
      s-=vb*60;
      t+=60;
    }
    
  if (s<60)
  {
    for(i=1;i<=60;i++)
    {
      s+=vc;
      t+=1;
      if(s>=60)
      {
        break;
      }
    }
  }
 
   if(s<60)
   {  
     s-=vd*60;
     t+=60;
   }
}
print t;
}

执行

awk -f water1.awk
#!/usr/bin/awk
function s_add(vx){
  if(s<60)
  {
    for(i=1;i<=60;i++)
    {
      s+=vx;
      t+=1;
      if(s>=60)
      {
        break;
      }
    }
  }

}

function s_dec(vx){
    if(s<60)
    {
      s-=vx*60;
      t+=60;
    }


}
BEGIN{
s=10;
va=60/180;
vb=60/240;
vc=60/300;
vd=60/360;
t=0;


while(s<60)
{
  s_add(va);
  s_dec(vb);
  s_add(vc);
  s_dec(vd);
}
print t;
}

最终版

#!/usr/bin/awk
BEGIN{
s=1/6;
v["a"]=1/10800;
v["b"]=-1/14400;
v["c"]=1/18000;
v["d"]=-1/21600;

while(s<1)
{
  for (i in v)
      for(n=1;n<=3600;n++)
         if(s<1)
         {
           s+=v[i];
           t+=1;
         }
}
print int(t/3600)"小时"int(t%3600/60)"分"t%3600%60"秒"
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容

  • Linux指令中文说明传送入口 整理自Linux指令中文说明 文本和数据进行处理的编程语言awk 是一种编程语言,...
    释闲人阅读 2,116评论 1 6
  • awk介绍awk变量printf命令:实现格式化输出操作符awk patternawk actionawk数组aw...
    哈喽别样阅读 1,562评论 0 4
  • 转载 原文的排版和内容都更加友好,并且详细,我只是在这里贴出了一部分留作自己以后参考和学习,如希望更详细了解AWK...
    XKirk阅读 3,200评论 2 25
  • awk: grep,sed,awk grep:文本过滤 sed:文本编辑 awk:文本格式化工具; 1 什么是aw...
    木林森阅读 1,771评论 0 16
  • 本章主要学习内容awk介绍 awk基本用法 awk变量 awk格式化 awk操作符 awk条件判断 a...
    楠人帮阅读 1,264评论 0 8