Última linha está errada ao dividir um arquivo com o awk

1

Eu tenho um arquivo de dados main.txt semelhante a este

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

Eu usei o seguinte snippet para dividir main.csv em arquivos menores por data.

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

e eu descobri o para o arquivo dividido data20130826.csv a última linha está incompleta,

...
20130826,dfasdfas,asdf2323
2013082

na verdade, as últimas poucas linhas (10 ou mais) da data 20130826 estão faltando, elas também não estão no data20130827.csv. Eu tentei desativar o buffer como na linha acima, mas não parece ajudar. Eu tenho certeza que o arquivo principal está OK. O que está errado? Estou usando o GNU Awk 4.0.1.

    
por user40129 22.02.2015 / 19:14

2 respostas

1

Só para esclarecer minha postagem original: Eu concordo com a Orion e duvido que isso seja um bug estranho. Eu também não me incomodaria com fflush. Eu acho que isso é apenas um problema de awk causado por dados. Especificamente, acho que você pode ter muitos descritores de arquivos abertos - um para cada data em seu arquivo. Ou talvez você tenha atingido um limite de buffer pelo mesmo motivo - muitos arquivos abertos. O fflush não fecha arquivos abertos - apenas libera buffers.

Então, quantas datas diferentes estão no arquivo de entrada? Isso é quantos arquivos abertos você terá:

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

- se for muito (centenas), então veja minha segunda sugestão sobre o fechamento de arquivos.

Duas sugestões:
1. Você tem certeza de que os dados são apenas texto simples, sem caracteres ocultos, como backspaces, e também terminações de linha normais no UNIX? Você pode grep as linhas prefixadas "20130826" para ver que elas parecem normais e realmente são todas as linhas separadas, ou seja,

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

- para confirmar que a contagem de linhas grep corresponde ao que está no arquivo de saída (ou não)

2. Se os dados de entrada estiverem classificados em ordem de data, você poderá tentar fechar os arquivos à medida que os escreve: Eu testei isso desde o meu post original e funcionou bem:

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

Esse código ainda funcionará se seu arquivo não estiver classificado por data, mas abrirá e fechará arquivos com mais frequência. Nesse caso, basta alterar "cat test01" para "sort test01" no início do comando.

Você nem sempre precisa fechar arquivos explicitamente ao usar o awk, mas eu sei por experiência que o awk costumava travar se você escrevesse muitos arquivos como este sem fechar nenhum deles. É possível que isso ainda se aplique como eu acho que está relacionado para um limite em descritores de arquivos abertos.

Além disso, ao adicionar esses arquivos, certifique-se de que eles não contenham dados antes de executar o comando. Fácil de esquecer quando as coisas não estão funcionando ...

    
por 23.02.2015 / 00:01
0

Tente:

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

Em gawk 4.0.1 , chamando fflush () sem nenhum argumento limpe a stdout. Você precisa chamar fflush() com a string vazia "" para fazer com que awk libere todos os arquivos e canais de saída abertos.

Com gawk 4.0.2 e posterior, se não houver argumento, ou se o argumento para fflush() for a string nula "" , então awk limpará os buffers de todos os arquivos e canais de saída abertos.

    
por 23.02.2015 / 02:43