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

Posted

技术标签:

【中文标题】使用 bash (sed/awk) 提取 CSV 文件中的行和列?【英文标题】:using bash (sed/awk) to extract rows AND columns in CSV files? 【发布时间】: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 设计用来做的最基本的事情。让我觉得这肯定比你到目前为止所描述的要多...... 【参考方案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 的原因。

以上是关于使用 bash (sed/awk) 提取 CSV 文件中的行和列?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 sed、awk 或 gawk 仅打印匹配的内容?

使用 bash、sed、awk 解析像 .ini 这样的文件

使用 sed / awk / bash 将缺失的行号填充到文件中

Linux bash 文本处理命令awk,sed,grep 用法

如何在bash脚本中使用Bash / Sed / Awk / Perl删除分隔字符串的最后一个元素[duplicate]

在普通bash中使用正则表达式提取子字符串