如果我有一个csv文件,是否有快速bash方式打印出任何单列的内容?可以安全地假设每行具有相同的列数,但每列的内容长度不同。
答案 0 :(得分:98)
你可以使用awk。将“$ 2”更改为您想要的第n列。
awk -F "\"*,\"*" '{print $2}' textfile.csv
答案 1 :(得分:71)
是肯定的。 cat mycsv.csv | cut -d ',' -f3
将打印第3列。
答案 2 :(得分:27)
我能够完成这项工作的最简单方法就是使用csvtool。我还有其他用例也可以使用csvtool,如果它们出现在列数据本身内,它可以适当地处理引号或分隔符。
csvtool format '%(2)\n' input.csv
用列号替换2将有效地提取您要查找的列数据。
答案 3 :(得分:13)
在这里登陆,希望从制表符分隔文件中提取。以为我会补充一下。
cat textfile.tsv | cut -f2 -s
其中-f2
提取2,非零索引列或第二列。
答案 4 :(得分:6)
这个问题的很多答案都很棒,有些人甚至研究过这些问题。 我想添加一个可以日常使用的简单答案......你大多数时候都会遇到这些极端情况(例如在引号等中使用逗号或逗号进行转义)。
FS(字段分隔符)是其值为dafaulted的变量 空间。因此,默认情况下,awk会在空格处为任何行拆分。
因此,使用BEGIN(在输入之前执行)我们可以将此字段设置为我们想要的任何内容......
awk 'BEGIN {FS = ","}; {print $3}'
上面的代码将在csv文件中打印第3列。
答案 5 :(得分:5)
您可以使用GNU Awk,请参阅this article of the user guide。
作为对文章(2015年6月)中提出的解决方案的改进,以下gawk命令允许双引号字段内的双引号;双引号用两个连续的双引号(“”)标记。此外,这允许空字段,但即使这样也无法处理多行字段。以下示例打印textfile.csv的第3列(通过c=3
):
#!/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)
注意使用dos2unix
将可能的DOS样式换行符(CRLF,即“\ r \ n”)和UTF-16编码(带字节顺序标记)转换为“\ n”和UTF-8(没有字节顺序标记),分别。标准CSV文件使用CRLF作为换行符,请参阅Wikipedia。
如果输入可能包含多行字段,则可以使用以下脚本。请注意使用特殊字符串分隔输出中的记录(因为默认分隔符换行符可能出现在记录中)。同样,以下示例打印textfile.csv的第3列(通过c=3
):
#!/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)
还有另一种解决问题的方法。 csvquote可以输出已修改的CSV文件的内容,以便转换字段中的特殊字符,以便可以使用常用的Unix文本处理工具来选择某个列。例如,以下代码输出第三列:
csvquote textfile.csv | cut -d ',' -f 3 | csvquote -u
csvquote
可用于处理任意大文件。
答案 6 :(得分:5)
其他答案效果很好,但由于您只使用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
然后你可以像这样拉出列(本例中的第一列):
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
所以这里有几件事情发生了:
while IFS=,
- 这就是说使用逗号作为IFS(内部字段分隔符),这是shell用来知道分隔字段(文本块)的内容。所以说IFS =,就像说“a,b”与“a b”相同,如果IFS =“”(默认情况下就是这样)。
read -a csv_line;
- 这就是说每行读一次,并创建一个数组,其中每个元素都被称为“csv_line”并将其发送到while循环的“do”部分< / p>
do echo "${csv_line[0]}";done < file
- 现在我们处于“做”阶段,我们说的是回显数组“csv_line”的第0个元素。在文件的每一行上重复此操作。 < file
部分只是告诉while循环从哪里读取。注意:记住,在bash中,数组是0索引的,因此第一列是第0个元素。
所以你有它,从shell中的CSV中拉出一列。其他解决方案可能更实用,但这个是纯粹的bash。
答案 7 :(得分:4)
[dumb @ one pts] $ cat&gt;文件#First我们将创建一个基本的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
[dumb @ one pts] $ awk -F,&#39; {print $ 1}&#39;文件
一个
1
一个
1
答案 8 :(得分:3)
我需要正确的CSV解析,而不是cut
/ awk
和祈祷。我在没有csvtool
的Mac上尝试这个,但mac确实带有ruby,所以你可以这样做:
echo "require 'csv'; CSV.read('new.csv').each {|data| puts data[34]}" | ruby
答案 9 :(得分:1)
如果没有完整的CSV解析器,则无法执行此操作。
答案 10 :(得分:1)
csvtool col 2 file.csv
其中2是您感兴趣的列
您也可以
csvtool col 1,2 file.csv
要做多列
答案 11 :(得分:1)
我想知道为什么到目前为止没有答案提到csvkit。
csvkit是一套命令行工具,用于转换并运行 CSV
我专门将其用于csv数据管理,到目前为止,我还没有发现使用cvskit无法解决的问题。
要从cvs文件中提取一个或多个列,可以使用工具箱中的csvcut
实用程序。要提取第二列,请使用以下命令:
csvcut -c 2 filename_in.csv > filename_out.csv
如果csv中的字符串用引号引起来,请使用q
选项添加引号字符:
csvcut -q '"' -c 2 filename_in.csv > filename_out.csv
使用pip install csvkit
或sudo apt install csvkit
安装。
答案 12 :(得分:1)
我认为最简单的方法是使用csvkit:
获取第二列:
csvcut -c 2 file.csv
但是,还有csvtool,可能还有许多其他的csv bash工具:
sudo apt-get install csvtool
(对于基于Debian的系统)
这将返回其中第一行具有“ ID”的列。
csvtool namedcol ID csv_file.csv
这将返回第四行:
csvtool col 4 csv_file.csv
如果要删除标题行:
csvtool col 4 csv_file.csv | sed '1d'
答案 13 :(得分:0)
暂时使用此代码,除非您计算“从stackoverflow剪切和粘贴”,否则它不会“快速”。
它在循环中使用$ {##}和$ {%%}运算符而不是IFS。它调用'err'和'die',并且只支持逗号,短划线和管道作为SEP字符(这就是我所需要的)。
err() { echo "${0##*/}: Error:" "$@" >&2; }
die() { err "$@"; exit 1; }
# Return Nth field in a csv string, fields numbered starting with 1
csv_fldN() { fldN , "$1" "$2"; }
# Return Nth field in string of fields separated
# by SEP, fields numbered starting with 1
fldN() {
local me="fldN: "
local sep="$1"
local fldnum="$2"
local vals="$3"
case "$sep" in
-|,|\|) ;;
*) die "$me: arg1 sep: unsupported separator '$sep'" ;;
esac
case "$fldnum" in
[0-9]*) [ "$fldnum" -gt 0 ] || { err "$me: arg2 fldnum=$fldnum must be number greater or equal to 0."; return 1; } ;;
*) { err "$me: arg2 fldnum=$fldnum must be number"; return 1;} ;;
esac
[ -z "$vals" ] && err "$me: missing arg2 vals: list of '$sep' separated values" && return 1
fldnum=$(($fldnum - 1))
while [ $fldnum -gt 0 ] ; do
vals="${vals#*$sep}"
fldnum=$(($fldnum - 1))
done
echo ${vals%%$sep*}
}
示例:
$ CSVLINE="example,fields with whitespace,field3"
$ $ for fno in $(seq 3); do echo field$fno: $(csv_fldN $fno "$CSVLINE"); done
field1: example
field2: fields with whitespace
field3: field3
答案 14 :(得分:0)
这是一个包含两列的csv文件示例
myTooth.csv
Date,Tooth
2017-01-25,wisdom
2017-02-19,canine
2017-02-24,canine
2017-02-28,wisdom
要获取第一列,请使用:
cut -d, -f1 myTooth.csv
f代表字段,d代表定界符
运行以上命令将产生以下输出。
输出
Date
2017-01-25
2017-02-19
2017-02-24
2017-02-28
仅获取第二列:
cut -d, -f2 myTooth.csv
这是输出 输出
Tooth
wisdom
canine
canine
wisdom
incisor
另一个用例:
您的csv输入文件包含10列,并且您希望第2至5列和第8列使用逗号作为分隔符。”
cut使用-f(表示“字段”)指定列,使用-d(表示“定界符”)指定分隔符。您需要指定后者,因为某些文件可能使用空格,制表符或冒号来分隔列。
cut -f 2-5,8 -d , myvalues.csv
cut是一个命令实用程序,下面是更多示例:
SYNOPSIS
cut -b list [-n] [file ...]
cut -c list [file ...]
cut -f list [-d delim] [-s] [file ...]
答案 15 :(得分:0)
您还可以使用while循环
IFS=,
while read name val; do
echo "............................"
echo Name: "$name"
done<itemlst.csv
答案 16 :(得分:0)
使用awk的简单解决方案。代替“colNum”,输入您需要打印的列数。
cat fileName.csv | awk -F ";" '{ print $colNum }'