使用bash(sed/awk)从CSV文件中提取行和列?

14

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最基本的设计功能。这让我觉得你所描述的情况肯定不止于此... - Ed Morton
11个回答

19
awk -F, 'NR > 1 { print $3 "," $4 "," $5 }' 

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


8
您可以设置 OFS=',',这样在打印输出时就不需要手动添加逗号来拼接字符串了。 - jordanm

9

试试这个:

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

2
最简单而优雅的解决方案。 - Dwight Spencer

6

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的解决方案了。 - icedwater
这个程序无法忽略引号中的逗号。例如,CSV行:““some,text”,1,2”将被解析为:“some”,“text”,“1”,“2”,而不是“some text”,“1”,“2”。 - gondo

6
使用cuttail命令:
tail -n +2 file.txt | cut -d ',' -f 3-

2
OP想要跳过第一行,所以我们使用了tail - Rubens

3
sed 1d file.csv | while IFS=, read first second rest; do echo "$rest"; done

2

这里有一个简单的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)
}

5
如果您设置 OFS=",",您可以简单地编写 print $3, $4, $5 - glenn jackman

2
这可能对你有用(GNU sed):
sed -r '1d;s/([^,]*,){2}//' file

2
perl -F, -lane 'if($.!=1){print join ",",@F[2,3,4];}' your_file

check here


2

试一试

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

或者这个

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

你能解释一下你的修复工作是怎么做的吗? - Jon Egerton
@JonEgerton,在awk中我添加了OFS,在sed中我使其更加清晰,以便新用户可以看到我正在匹配的内容。在之前的答案中,正则表达式很短,但对于正则表达式的新用户来说很难理解。我的可能不完美,但至少可以看到它们在做什么。而且它们是有效的。 - Mirage

1
我已经为这种任务创建了一个包 - gumba。如果您熟悉Coffeescript,可以尝试使用它。
cat file.csv | tail -n +2 | \
gumba "words(',').take((words)-> words.last(3)).join(',')"`

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接