一个文件data.csv
有以下数据
1,avocado,mexican green fruit
1,kiwi,green fruit
1,banana,yellow fruit
1,mango,yellow fruit
为了将数据组织成水果类别,我已经完成了
awk -F ',' '{print >> ($3 ".csv")}' data.csv
它创建了 3 个文件,mexican green fruit.csv
, green fruit.csv
,yellow fruit.csv
我希望这些文件名称中的空格替换为下划线_
所以,文件名应该是mexican_green_fruit.csv
,,green_fruit.csv
yellow_fruit.csv
需要这一衬里的帮助awk
才能做到这一点
寻找awk
唯一的答案
答案1
GNU awk 的仅 awk 答案(按照 OP 的要求)将是:
awk -F',' '{print > gensub(/[[:space:]]+/,"_","g",$3) ".csv"}' data.csv
如果您的输入足够小以至于不能超过“打开文件太多”阈值,则任何 POSIX awk 的仅 awk 答案将是:
awk -F',' '{out=$3 ".csv"; gsub(/[[:space:]]+/,"_",out); print > out}' data.csv
如果您可能超过“打开文件过多”阈值,则任何 POSIX awk 的仅 awk 答案将是:
awk -F',' '{out=$3 ".csv"; gsub(/[[:space:]]+/,"_",out); if (!seen[$3]++) printf "" > out; print >> out; close(out)}' data.csv
但最后一个会很慢,因为它会为每次写入关闭并重新打开输出文件,并且假设您可以将每个$3
值存储在内存中。您可以通过仅在输出文件发生更改时关闭输出文件来提高效率:
awk -F',' '$3 != prev {close(out); out=$3 ".csv"; gsub(/[[:space:]]+/,"_",out); if (!seen[$3]++) printf "" > out; prev=$3} {print >> out}' data.csv
如果您对不只使用 awk 的答案感到满意,那么使用任何 POSIX awk、排序和剪切的 DSU(装饰/排序/取消装饰)习惯用法,以下内容将针对任何大小的输入文件有效且稳健地工作可以sort
处理(并且它被设计为使用请求分页等来处理极大的文件),并且对于任意数量的输出文件:
$ cat tst.sh
#!/usr/bin/env bash
awk '
BEGIN{ FS=OFS="," }
{ print $3,NR,$0 }
' "${@:-}" |
sort -t',' -k1,1 -k2,2n |
cut -d',' -f3- |
awk '
BEGIN{ FS=OFS="," }
$3 != prev {
close(out)
out = $3 ".csv"
gsub(/[[:space:]]+/,"_",out)
prev = $3
}
{ print > out }
'
$ ./tst.sh data.csv
$ head *.csv
==> data.csv <==
1,avocado,mexican green fruit
1,kiwi,green fruit
1,banana,yellow fruit
1,mango,yellow fruit
==> green_fruit.csv <==
1,kiwi,green fruit
==> mexican_green_fruit.csv <==
1,avocado,mexican green fruit
==> yellow_fruit.csv <==
1,banana,yellow fruit
1,mango,yellow fruit
有关 DSU 的更多信息,请参阅https://stackoverflow.com/questions/71691113/how-to-sort-data-based-on-the-value-of-a-column-for-part-multiple-lines-of-af/71694367#71694367。
答案2
可以用一个函数来完成,例如:
awk -F, '
function csvfile(name) {
gsub(/[[:space:]]+/, "_", name)
return name".csv"
}
{print >> csvfile($3)}'
此处将每个序列的一个或多个空白字符(包括空格、制表符、cr...)替换为_
。
答案3
(使用 gnu awk 或类似的)你可以按照以下方式运行一些东西
awk -F, '{print > gensub(/ /,"_","g",$3)".csv"}' ex.csv
gensub
是一个函数式的sub
——稍微容易编写。>
可能比>>
除非您在执行此命令之前创建了一些 csv 更好。- 如果我们有数百万个不同的 3 美元值,我们可能会遇到问题。
编辑:应对新的要求(实际上是一个新的问题)
awk -F, '
NF == 0 {next}
!seen[$3]++ {print "Quantity, f..., c..." > gensub(/ /,"_","g",$3)".csv"}
{print > gensub(/ /,"_","g",$3)".csv"}
' ex.csv