我正在tty Linux上处理一些巨大的CSV文件(>500 MB(。我的数据格式如下:
A, XYZ
A, ZSY
A, TVT
B, GHJ
B, XYZ
C, XYZ
C, TVT
输出应如下所示。
A, XYZ, ZSY, TVT
B, GHJ, XYZ, nil
C, XYZ, TVT, nil
第一列充当键,并将所有其他相应的行转换为列。我只有标准的Unix工具(+perl(。
有什么标准的Unix解决方案可以务实地解决这个问题吗?
如果您不关心输出的顺序应该与Input_file相同,那么下面的内容可能会对您有所帮助。
awk 'BEGIN{FS=", ";OFS=","}{a[$1]=a[$1]?a[$1] OFS $NF:$NF} END{for(i in a){print i,a[i]}}' Input_file
OR
awk '
BEGIN{ FS=", ";OFS="," }
{
a[$1]=a[$1]?a[$1] OFS $NF:$NF
}
END{
for(i in a){ print i,a[i] }
}' Input_file
第二个解决方案:如果您希望输出顺序与Input_file的顺序相同,那么以下内容可能会对您有所帮助。
awk '
BEGIN { FS=", ";OFS="," }
!b[$1]++{ c[++count]=$1 }
{
a[$1]=a[$1]?a[$1] OFS $NF:$NF
}
END{
for(i=1;i<=count;i++){ print c[i],a[c[i]] }
}' Input_file
这是awk
的另一个解决方案,取决于您的数据是否为第一列排序
排序:
awk -F',' -v OFS=',' '{if(a!=$1){printf (a!="")?"n"$1:$1;a=$1} printf "%s%s",OFS,$2}END{print}'
简要说明,
if(a!=$1){printf (a!="")?"n"$1:$1;a=$1}
:已定义的a
,如果未定义则打印printf "%s%s",OFS,$2
:始终打印以下列
未分拣
sort -sk1,1 file | awk -F',' -v OFS=',' '{if(a!=$1){printf (a!="")?"n"$1:$1;a=$1} printf "%s%s",OFS,$2}END{print}'
使用sort -sk1,1
对第一列进行排序,然后执行与排序列相同的操作。
这只需在找到每个唯一密钥时打印其值,这样您就不必将整个巨大的文件存储在内存中:
$ cat tst.awk
BEGIN {
FS = "[[:space:]]*,[[:space:]]*"
OFS = ", "
}
$1 != prev {
if ( NR > 1 ) {
prt()
}
prev = $1
}
{
vals[++numVals] = $2
}
END {
prt()
}
function prt( numCols, colNr, val) {
numCols = 3
printf "%s", prev
for (colNr=1; colNr<=numCols; colNr++) {
val = (colNr in vals ? vals[colNr] : "nil")
printf "%s%s", OFS, val
}
print ""
delete vals
numVals = 0
}
$ awk -f tst.awk file
A, XYZ, ZSY, TVT
B, GHJ, XYZ, nil
C, XYZ, TVT, nil