用awk分割文件时最后一行是错误的

用awk分割文件时最后一行是错误的

main.txt我有一个如下所示的数据文件

20130826,aaaaaaaaaaaaaa,bbbbbbb
20130826,sdfasdfasdfas,sdfasdfasd
20130826,dfasdfas,asdf2323
...
20130827,sfasdfasdfasd,sdfasdfwea

我使用以下 awk 片段main.csv按日期分割成较小的文件。

cat test01 | stdbuf -oL -eL awk -F',' '{print $2","$3 >> "data"$1".csv"; fflush()}'

我发现分割文件 data20130826.csv 的最后一行不完整,

...
20130826,dfasdfas,asdf2323
2013082

事实上,日期 20130826 的最后几行(10 左右)都丢失了,它们也不在 data20130827.csv 中。我尝试按照上面的行关闭缓冲,但这似乎没有帮助。我确信主文件没问题。出了什么问题?我正在使用 GNU Awk 4.0.1。

答案1

只是为了澄清我原来的帖子:我同意 Orion 的观点,并怀疑这是一个 awk 错误。我也不会为 fflush 烦恼。我认为这只是数据引起的 awk 问题。具体来说,我认为您可能有太多打开的文件描述符 - 文件中的每个日期都有一个。或者,您可能出于同样的原因达到了缓冲区限制 - 打开的文件太多。 fflush 不会关闭打开的文件 - 它只是刷新缓冲区。

那么输入文件中有多少个不同的日期?这就是您将有多少个打开的文件:

cut -d"," -f1 test01 | sort | uniq | wc -l

- 如果很多(数百个),那么请参阅我关于随时关闭文件的第二个建议。

两个建议:
1. 您确定数据只是纯文本,没有任何隐藏字符(如退格符)并且也具有正常的 UNIX 行结尾吗?你能 grep 出前缀为“20130826”的行来看看它们看起来正常并且实际上都是单独的行,即

cat test01 | grep "^20130826"
- and also run
cat test01 | grep -c "^20130826"

- 确认 grep 行数与输出文件中的内容匹配(或不匹配)

2.如果输入数据按日期顺序排序,那么您可以尝试在编写文件时关闭文件:自从我最初的帖子以来我对此进行了测试,它工作得很好:

cat test01 | awk -F"," '{prevfile=ofile; ofile=sprintf("data%s.csv",$1);
             if (NR > 1 && ofile != prevfile) close(prevfile); print $2","$3 >> ofile}'

如果您的文件未按日期排序,此代码仍然有效,但会更频繁地打开和关闭文件。在这种情况下,只需在命令开头将“cat test01”更改为“sort test01”即可。

使用 awk 时,您并不总是需要显式关闭文件,但根据我的经验,如果您编写了很多这样的文件而不关闭其中任何一个文件,awk 就会崩溃,这可能仍然适用,因为我认为它与限制有关在打开的文件描述符上。

此外,当您附加到这些文件时,请确保在运行命令之前它们不包含任何数据。当事情不顺利时很容易忘记......

答案2

尝试:

$ cat test01 |
stdbuf -oL -eL awk -F',' '{print $2","$3 >> "data"$1".csv"; fflush("")}'

在 中gawk 4.0.1,呼叫fflush()没有任何参数只刷新标准输出。您需要fflush()使用空字符串进行调用""才能awk刷新所有打开的输出文件和管道。

使用gawk 4.0.2和 以后,如果没有参数,或者参数为fflush()空字符串"",则awk刷新所有打开的输出文件和管道的缓冲区。

相关内容