程序员

先死后活,死去活来

shell脚本:统计订单信息

今天跟一同事聊天,他面试时,被问到这么一个问题。

基本需求

请写一个shell脚本实现以下功能:在一个日志文件中,存放着用户名和订单交易额,请输出交易次数最多的用户名。
其日志文件大致如下:

FAN:12
LI:34
FAN:21
FAN:45
LI:123

其中第一列表示用户名,第二列表示交易额,列于列之间通过”:”隔开。
这个问题可以通过一行shell代码就可以实现。
解题思路:
需要将第一列数据取出来,然后统计出重复的个数,然后降序排列,取出第一个就可以。
代码如下:

#!/bin/bash
cat log | awk -F ":" '{print $1}' | sort | uniq -c | sort -nr | head -1 | awk '{print $2}'

代码解释:

  • awk -F “:” ‘{print $1}’
    按照”:”作为分隔符,取出第一列数据。 -F 表示field-seperator
  • sort
    这个为下一步的uniq做准备。使一样的用户名排在相邻行,默认是按升序排列。
  • uniq -c
    去除重复行,并统计重复的行数。uniq命令默认是相邻行去重,因此需要去重。其输出结果如下:
    这里写图片描述
    对于uniq这个命令,-d(duplicate)表示仅显示重复行,-u(unduplicate)仅显示非重复行
    这里写图片描述
  • sort -nr
    按照数值大小降序排列。sort命令默认情况下是按照字符大小进行排序,即出现10<2的情况,因为’1’<’2’。使用-n参数使数值按照整数对待。sort命令默认按照升序进行排序,-r(reverse)参数表示按降序排列。
  • head -1
    取头上第一行。
  • awk ‘{print $2}’
    打印出用户名,这里之所以写成2是因为,uniq -c这个的输出第一列表示统计的重复的行数,第二列才是用户名。

扩展一

输出交易次数最多的用户对应的交易额。
解题思路:
上一步已经找到这个用户,下面需要将这个用户的记录全部找出来,然后将每次的交易额累加起来。
代码实现如下:

#!/bin/bash
name=`cat log | awk -F ":" '{print $1}' | sort | uniq -c | sort -nr | head -1 | awk '{print $2}'`
#name=$(cat log | awk -F ":" '{print $1}' | sort | uniq -dc | sort -nr | head -1 | awk '{print $2}')
#echo ${name}
result=`cat log | grep ${name} | awk -F ":" '{print $2}' | awk '{sum+=$1} END {print sum}'`
echo ${name} ${result}

代码解释:
(1)要给变量赋值,要么使用符号“将命令围住,要么使用$()。

(2)cat log | grep ${name}
从log文件中只抽取出,上一步中找到的用户名相关记录。

(3)awk -F “:” ‘{print $2}’
得到这个用户的所有交易额

(4)awk ‘{sum+=$1} END {print sum}’
将用户的所有交易额累加

扩展二

有的时候交易次数最多的总交易额未必最多。如这个log文件中,LI的交易次数少,但是其交易额多。现在需要找出交易额最多的用户名,及其总交易额。
解题思路:
首先需要得到所有用户的用户名,然后逐个算出每个用户的总交易额,然后求出最大的,就OK了。这里,用户名数组和总交易额数组,其下标是对应的。如:userName[0]中存放的是用户名,则userTrading[0]存放的是这个用户的总交易额。
代码如下:

#!/bin/bash
userName=($(cat log | awk -F ":" '{print $1}' | sort | uniq))
length=${#userName[*]}
#for user in ${userName[@]}
#do
#  echo ${user}
#done
i=0
max=0
while [ $i -lt ${length} ]
do
  userTrading[$i]=`cat log | grep ${userName[$i]} | awk -F ":" '{print $2}' | awk '{sum+=$1} END {print sum}'`
  if [ ${userTrading[$max]} -lt ${userTrading[$i]} ] 
  then
    max=$i
  fi
  i=$(($i+1))
done
echo ${userName[$max]} ${userTrading[$max]}

代码解释:
(1)将shell命令的执行结果存放到数组中

userName=($(cat log | awk -F ":" '{print $1}' | sort | uniq))

shell脚本的语法可谓奇葩,有的时候很随意,有的时候很严格,得到数组必须要这么写。
其执行结果如下所示:
这里写图片描述
(2)得到数组的长度

length=${#userName[*]}
#length=${#userName[@]}

这里写图片描述
上面两种写法都可以。
(3)while循环
在上例中实现了两种循环,一种是for循环,得到数组中的内容,另一种是while循环,按照下标去访问。

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fan2012huan/article/details/48503821
个人分类: linux
想对作者说点什么? 我来说一句

shell统计文本行数脚本

2012年06月04日 813B 下载

深入学习shell脚本艺术

2011年02月22日 2.99MB 下载

没有更多推荐了,返回首页

不良信息举报

shell脚本:统计订单信息

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭