【问题标题】:using bash (sed/awk) to extract rows AND columns in CSV files?使用 bash (sed/awk) 提取 CSV 文件中的行和列?
【发布时间】:2013-01-07 16:36:57
【问题描述】:

bash 是否能够处理从 csv 文件中提取行和列?希望我不必求助于 python..

我的 5 列 csv 文件如下所示:

Rank,Name,School,Major,Year
1,John,Harvard,Computer Science,3
2,Bill,Yale,Political Science,4
3,Mark,Stanford,Biology,1
4,Jane,Princeton,Electrical Engineering,3
5,Alex,MIT,Management Economics,2

我只想提取第 3、4、5 列的内容,忽略第一行,所以输出如下:

Harvard,Computer Science,3
Yale,Political Science,4
Stanford,Biology,1
Princeton,Electrical Engineering,3
MIT,Management Economics,2

到目前为止,我只能让 awk 打印出我的 CSV 文件的每一行或每一列,而不是像这种情况下的特定列/行! bash 可以这样做吗?

【问题讨论】:

  • 奇怪的是,您很难让 awk 来执行此操作,因为打印字段(列)和行(记录)是 awk 设计用来做的最基本的事情。让我觉得这肯定比你到目前为止所描述的要多......

标签: bash csv sed awk


【解决方案1】:

试试这个

awk -F, 'NR > 1 { OFS=",";print $3, $4, $5 }' temp.txt

或者这个

sed -re '1d;s/^[0-9],\w+,//g' temp.txt

【讨论】:

  • 您能否解释一下您的修复程序在做什么?
  • @JonEgerton,在 awk 中我添加了 OFS,在 sed 中我更加清晰,以便新用户可以看到我匹配的内容。在以前的答案中,正则表达式很短,但对于正则表达式的新用户来说很难理解。我的可能并不完美,但至少可以看到他们在做什么。他们工作
【解决方案2】:
grep '^,' outlook.contacts.csv | sed 's/^,\([^,]*\),[^,]*,\([^,]*\),.*/\1 \2/'

获取所有以, 开头的行,然后使用sed 将空白字段替换为名字和名字。

出于某种原因,一旦您将其粘贴到此行,请小心,因此您最好手动小心操作。

grep '^,' outlook.contacts.csv | sed 's/^,([^,]),[^,],([^,]),./\1 \2/'

【讨论】:

    【解决方案3】:

    试试这个:

    tail -n+2 file.csv | cut --delimiter=, -f3-5
    

    【讨论】:

    • 迄今为止最简单优雅的解决方案。
    【解决方案4】:

    我已经为这类任务创建了包 - gumba 如果您对 coffeescript 感到满意,可以尝试一下

    cat file.csv | tail -n +2 | \
    gumba "words(',').take((words)-> words.last(3)).join(',')"`
    

    【讨论】:

      【解决方案5】:

      这可能对你有用(GNU sed):

      sed -r '1d;s/([^,]*,){2}//' file
      

      【讨论】:

        【解决方案6】:
        perl -F, -lane 'if($.!=1){print join ",",@F[2,3,4];}' your_file
        

        查看here

        【讨论】:

          【解决方案7】:
          sed 1d file.csv | while IFS=, read first second rest; do echo "$rest"; done
          

          【讨论】:

            【解决方案8】:

            Bash 解决方案;

            使用 IFS

            #!/bin/bash
            while IFS=',' read -r rank name school major year; do
                echo -e "Rank\t: $rank\nName\t: $name\nSchool\t: $school\nMajor\t: $major\nYear\t: $year\n"
            done < file.csv
            IFS=$' \t\n'
            

            使用字符串操作和数组

            #!/bin/bash
            declare -a arr
            while read -r line; do
                arr=(${line//,/ })
                printf "Rank\t: %s\nName\t: %s\nSchool\t: %s\nMajor\t: %s\nYear\t: %s\n" ${arr[@]}
            done < file.csv
            

            【讨论】:

            • 相当笨拙,但我喜欢使用数组,我可能会在某些时候再次提及。更不用说这是一个仅限 bash 的解决方案。
            • 这无法忽略引号中的逗号。示例 csv 行:"some, text",1,2 将被解析为:sometext12 而不是 some text12
            【解决方案9】:

            给你,一个简单的 AWK 程序。

            #!/usr/bin/awk -f
            
            BEGIN {
                # set field separator to comma to split CSV fields
                FS = ","
            }
            
            # NR > 1 skips the first line
            NR > 1 {
                # print only the desired fields
                printf("%s,%s,%s\n", $3, $4, $5)
            }
            

            【讨论】:

            • 如果设置OFS=",",可以直接写print $3, $4, $5
            【解决方案10】:
            awk -F, 'NR > 1 { print $3 "," $4 "," $5 }' 
            

            NR 是当前行号,而 $3、$4 和 $5 是由 -F 给出的字符串分隔的字段

            【讨论】:

            • 您可以设置OFS=',',这样您就不必在打印中连接逗号。
            【解决方案11】:

            使用cuttail

            tail -n +2 file.txt | cut -d ',' -f 3-
            

            【讨论】:

            • OP 想跳过第一行,这就是我们使用tail 的原因。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-08-13
            • 1970-01-01
            • 2013-11-09
            • 2011-09-10
            • 2012-04-30
            • 2019-12-23
            • 2014-08-01
            相关资源
            最近更新 更多