如果我有一个csv文件,是否有快速bash方式打印出任何单个列的内容?可以安全地假设每行具有相同的列数,但每列的内容将具有不同的长度.
syn*_*tel 111
你可以使用awk.将"$ 2"更改为您想要的第n列.
awk -F "\"*,\"*" '{print $2}' textfile.csv
Run Code Online (Sandbox Code Playgroud)
小智 77
是.cat mycsv.csv | cut -d ',' -f3将打印第3列.
Sam*_*mar 37
我能够完成这项工作的最简单方法就是使用csvtool.我还有其他用例也可以使用csvtool,如果它们出现在列数据本身中,它可以适当地处理引号或分隔符.
csvtool format '%(2)\n' input.csv
Run Code Online (Sandbox Code Playgroud)
用列号替换2将有效地提取您要查找的列数据.
cev*_*ris 13
登陆这里寻找从标签分离文件中提取.以为我会补充一下.
cat textfile.tsv | cut -f2 -s
Run Code Online (Sandbox Code Playgroud)
其中-f2提取2,非零索引列或第二列.
Str*_*ker 10
这是一个包含 2 列的 csv 文件示例
myTooth.csv
Run Code Online (Sandbox Code Playgroud)
Date,Tooth
2017-01-25,wisdom
2017-02-19,canine
2017-02-24,canine
2017-02-28,wisdom
Run Code Online (Sandbox Code Playgroud)
要获取第一列,请使用:
cut -d, -f1 myTooth.csv
Run Code Online (Sandbox Code Playgroud)
f 代表字段,d 代表分隔符
运行上述命令将产生以下输出。
输出
Date
2017-01-25
2017-02-19
2017-02-24
2017-02-28
Run Code Online (Sandbox Code Playgroud)
仅获取第二列:
cut -d, -f2 myTooth.csv
Run Code Online (Sandbox Code Playgroud)
这是输出 输出
Tooth
wisdom
canine
canine
wisdom
incisor
Run Code Online (Sandbox Code Playgroud)
另一个用例:
您的 csv 输入文件包含 10 列,您需要第 2 到第 5 列和第 8 列,使用逗号作为分隔符”。
cut 使用 -f(意思是“字段”)来指定列,使用 -d(意思是“分隔符”)来指定分隔符。您需要指定后者,因为某些文件可能使用空格、制表符或冒号来分隔列。
cut -f 2-5,8 -d , myvalues.csv
Run Code Online (Sandbox Code Playgroud)
cut 是一个命令实用程序,这里有更多示例:
SYNOPSIS
cut -b list [-n] [file ...]
cut -c list [file ...]
cut -f list [-d delim] [-s] [file ...]
Run Code Online (Sandbox Code Playgroud)
这个问题的许多答案都很棒,有些人甚至研究过这些问题.我想添加一个简单的答案,可以在日常使用中...你大多数情况下进入那些极端情况(比如在引号中转义逗号或逗号等).
FS(字段分隔符)是一个变量,其值是空间的dafaulted.因此,默认情况下,awk会在空格处为任何行拆分.
所以使用BEGIN(在输入之前执行)我们可以将此字段设置为我们想要的任何内容...
awk 'BEGIN {FS = ","}; {print $3}'
Run Code Online (Sandbox Code Playgroud)
上面的代码将在csv文件中打印第3列.
小智 6
首先,我们将创建一个基本的 CSV
[dumb@one pts]$ cat > file
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
Run Code Online (Sandbox Code Playgroud)
然后我们得到第一列
[dumb@one pts]$ awk -F , '{print $1}' file
a
1
a
1
Run Code Online (Sandbox Code Playgroud)
其他答案运行良好,但由于您只使用bash shell请求解决方案,您可以这样做:
AirBoxOmega:~ d$ cat > file #First we'll create a basic CSV
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
Run Code Online (Sandbox Code Playgroud)
然后你可以拉出列(本例中的第一列),如下所示:
AirBoxOmega:~ d$ while IFS=, read -a csv_line;do echo "${csv_line[0]}";done < file
a
1
a
1
a
1
a
1
a
1
a
1
Run Code Online (Sandbox Code Playgroud)
所以这里有几件事情:
while IFS=, - 这就是说使用逗号作为IFS(内部字段分隔符),这是shell用来知道分隔字段(文本块)的内容.所以说IFS =,就像说"a,b"与"a b"相同,如果IFS =""(默认情况下是这样).
read -a csv_line; - 这就是说每行读一次,然后创建一个数组,其中每个元素都被称为"csv_line"并将其发送到while循环的"do"部分
do echo "${csv_line[0]}";done < file - 现在我们处于"do"阶段,我们说的是回显数组"csv_line"的第0个元素.在文件的每一行上重复此操作.该< file部分只是告诉while循环从哪里读取.注意:记住,在bash中,数组是0索引的,因此第一列是第0个元素.
所以你有它,从shell中的CSV中拉出一列.其他解决方案可能更实用,但这个是纯粹的bash.
您可以使用GNU Awk,请参阅用户指南的这篇文章.作为对文章(2015年6月)中提出的解决方案的改进,以下gawk命令允许双引号字段内的双引号; 双引号用两个连续的双引号("")标记.此外,这允许空字段,但即使这样也无法处理多行字段.以下示例打印c=3textfile.csv 的第3列(via ):
#!/bin/bash
gawk -- '
BEGIN{
FPAT="([^,\"]*)|(\"((\"\")*[^\"]*)*\")"
}
{
if (substr($c, 1, 1) == "\"") {
$c = substr($c, 2, length($c) - 2) # Get the text within the two quotes
gsub("\"\"", "\"", $c) # Normalize double quotes
}
print $c
}
' c=3 < <(dos2unix <textfile.csv)
Run Code Online (Sandbox Code Playgroud)
注意dos2unix用于将可能的DOS样式换行符(CRLF,即"\ r \n")和UTF-16编码(带字节顺序标记)分别转换为"\n"和UTF-8(不带字节顺序标记).标准CSV文件使用CRLF作为换行符,请参阅Wikipedia.
如果输入可能包含多行字段,则可以使用以下脚本.请注意使用特殊字符串来分隔输出中的记录(因为默认分隔符换行符可能出现在记录中).同样,以下示例打印c=3textfile.csv 的第3列(via ):
#!/bin/bash
gawk -- '
BEGIN{
RS="\0" # Read the whole input file as one record;
# assume there is no null character in input.
FS="" # Suppose this setting eases internal splitting work.
ORS="\n####\n" # Use a special output separator to show borders of a record.
}
{
nof=patsplit($0, a, /([^,"\n]*)|("(("")*[^"]*)*")/, seps)
field=0;
for (i=1; i<=nof; i++){
field++
if (field==c) {
if (substr(a[i], 1, 1) == "\"") {
a[i] = substr(a[i], 2, length(a[i]) - 2) # Get the text within
# the two quotes.
gsub(/""/, "\"", a[i]) # Normalize double quotes.
}
print a[i]
}
if (seps[i]!=",") field=0
}
}
' c=3 < <(dos2unix <textfile.csv)
Run Code Online (Sandbox Code Playgroud)
还有另一种解决问题的方法.csvquote可以输出已修改的CSV文件的内容,以便转换字段中的特殊字符,以便可以使用通常的Unix文本处理工具来选择某个列.例如,以下代码输出第三列:
csvquote textfile.csv | cut -d ',' -f 3 | csvquote -u
Run Code Online (Sandbox Code Playgroud)
csvquote 可用于处理任意大文件.
我需要正确的 CSV 解析,而不是cut/awk和祈祷。我正在没有csvtool.
echo "require 'csv'; CSV.read('new.csv').each {|data| puts data[34]}" | ruby
Run Code Online (Sandbox Code Playgroud)
我想知道为什么到目前为止没有一个答案提到 csvkit。
csvkit 是一套用于转换和使用 CSV 的命令行工具
我专门将它用于 csv 数据管理,到目前为止,我还没有发现使用 cvskit 无法解决的问题。
要从 cvs 文件中提取一列或多列,您可以使用csvcut工具箱中的实用程序。要提取第二列,请使用以下命令:
csvcut -c 2 filename_in.csv > filename_out.csv
Run Code Online (Sandbox Code Playgroud)
如果 csv 中的字符串带引号,请使用以下q选项添加引号字符:
csvcut -q '"' -c 2 filename_in.csv > filename_out.csv
Run Code Online (Sandbox Code Playgroud)
使用pip install csvkit或安装sudo apt install csvkit。