在命令行处理 CSV 文件

作者: 桐山少年 | 来源:发表于2018-11-08 14:45 被阅读1次

    由于这些年 Python 和机器学习的流行,一说到 CSV 文件,马上想到的工具是 pandas。pandas 很好,但是很多简单的处理,用一个更轻量的工具可以实现,而且几乎所有的 Unix/Linux 系统都附带了这工具(当然也包括 macOS)。这就是 awk。我这篇要谈的是 awk 的几个使用例子。

    假设有一个文件 bangumi.csv 内容如下:

    日期 番名 更新集数 播放(万)
    周一 书店里的骷髅店员本田 第5话 242.6
    周二 关于我转生变成史莱姆这档事 第6话 2438.7
    周三 强风吹拂 第6话 207.6
    周四 青春猪头少年不会梦到兔女郎学姐 第6话 1847.9
    周五 魔法禁书目录-第三季 第5话 1291.9
    周六 JOJO的奇妙冒险-黄金之风 第5话 851.7
    周日 刀剑神域-Alicization 第5话 2170.1
    

    以下的各个例子都是对这个文件的处理。

    一、输出某些列

    例1

    只想要番名那一列,可以这样用。

    awk '{print $2}' bangumi.csv
    

    结果:

    番名
    书店里的骷髅店员本田
    关于我转生变成史莱姆这档事
    强风吹拂
    青春猪头少年不会梦到兔女郎学姐
    魔法禁书目录-第三季
    JOJO的奇妙冒险-黄金之风
    刀剑神域-Alicization
    

    注意点:

    1. awk 默认用空格或 \t 来分隔列。列分隔符可以用 -F 选项来指定。
    2. 列从 1 开始计数,$1表示第一列,$NF表示最后一列, $(NF-1)表示倒数第二列,$0表示整行。

    例2

    想要番名和日期那两列,并且调换下顺序,用,分隔,并且标出行号。

    awk '{print NR ". " $2 "," $1}' bangumi.csv
    

    结果:

    1. 番名,日期
    2. 书店里的骷髅店员本田,周一
    3. 关于我转生变成史莱姆这档事,周二
    4. 强风吹拂,周三
    5. 青春猪头少年不会梦到兔女郎学姐,周四
    6. 魔法禁书目录-第三季,周五
    7. JOJO的奇妙冒险-黄金之风,周六
    8. 刀剑神域-Alicization,周日
    

    注意点:

    1. 双引号内的内容会原样输出。
    2. 变量 NR 表示行号。

    二、输出某些行

    例3

    例2 中的结果包含了表头,这里修正一下,把表头去掉,只留下内容。

    awk 'NR > 1 {print NR - 1 ". " $2 "," $1}' bangumi.csv
    

    结果:

    1. 书店里的骷髅店员本田,周一
    2. 关于我转生变成史莱姆这档事,周二
    3. 强风吹拂,周三
    4. 青春猪头少年不会梦到兔女郎学姐,周四
    5. 魔法禁书目录-第三季,周五
    6. JOJO的奇妙冒险-黄金之风,周六
    7. 刀剑神域-Alicization,周日
    

    注意点:

    1. 加在大扩号前面的是对行的过滤条件。
    2. 因为输出少了一行,NR - 1修正一下行号。

    例4

    输出更新到第5话的日期和番名。

    awk '/第5话/ {print $1,$2}' bangumi.csv
    

    结果:

    周一 书店里的骷髅店员本田
    周五 魔法禁书目录-第三季
    周六 JOJO的奇妙冒险-黄金之风
    周日 刀剑神域-Alicization
    

    注意点:

    1. 行过滤条件可以用正则表达式
    2. 正则表达式要写在一对/中间

    三、统计

    例5

    在例4 的基础上,多输出一个行号。

    错误示范:如果用 NR 输出行号,结果会是

    # awk '/第5话/ {print NR ". " $1,$2}' bangumi.csv 
    
    2. 周一 书店里的骷髅店员本田
    6. 周五 魔法禁书目录-第三季
    7. 周六 JOJO的奇妙冒险-黄金之风
    8. 周日 刀剑神域-Alicization
    

    正确的做法是用一个变量来计数:

    awk '/第5话/ {n+=1; print n ". " $1,$2}' bangumi.csv
    

    结果:

    1. 周一 书店里的骷髅店员本田
    2. 周五 魔法禁书目录-第三季
    3. 周六 JOJO的奇妙冒险-黄金之风
    4. 周日 刀剑神域-Alicization
    

    注意点:

    1. ; 分隔多个动作。
    2. 变量初始值默认为空,空值用来计算的话,当0来处理。

    例6

    让例5 中的行号,从零开始。

    awk 'BEGIN {n=-1} /第5话/ {n+=1; print n ". " $1,$2}'  bangumi.csv
    

    结果:

    0. 周一 书店里的骷髅店员本田
    1. 周五 魔法禁书目录-第三季
    2. 周六 JOJO的奇妙冒险-黄金之风
    3. 周日 刀剑神域-Alicization
    

    注意点:

    1. BEGIN的内容只在最开始的时候执行一次。

    例7

    把所有番剧的播放量累加一下,附在最后。

    awk '{if (NR>1) s+=$4; print $0} END{print "----------------"; print "总播放量: " s "万"}' bangumi.csv
    

    结果:

    日期 番名 更新集数 播放(万)
    周一 书店里的骷髅店员本田 第5话 242.6
    周二 关于我转生变成史莱姆这档事 第6话 2438.7
    周三 强风吹拂 第6话 207.6
    周四 青春猪头少年不会梦到兔女郎学姐 第6话 1847.9
    周五 魔法禁书目录-第三季 第5话 1291.9
    周六 JOJO的奇妙冒险-黄金之风 第5话 851.7
    周日 刀剑神域-Alicization 第5话 2170.1
    ----------------
    总播放量: 9050.5万
    

    注意点:

    1. 利用if ()语句可以做细致的过滤。
    2. END的内容只在前面的动作执行完之后执行一次。

    如果想更多得了解「变量」「动作」等概念,可以参考一下阮一峰的这篇博客 awk 入门教程

    相关文章

      网友评论

        本文标题:在命令行处理 CSV 文件

        本文链接:https://www.haomeiwen.com/subject/nrdwxqtx.html