Reformatando tabelas

2

Eu tenho o seguinte tipo de tabelas:

ID   date     DailyFlow
a 1972-01-01 17.0265761797993
b 1972-01-02 17.200476457399
c 1972-01-03 17.2926436045271
d 1972-01-04 17.3900277599829
e 1972-01-05 17.5987080931028
f 1972-01-06 17.6334881486229
g 1972-01-07 17.7030482596626
...

Gostaria de reformatá-los da seguinte forma:

YYYY    DDD sim
1972    1   17.0265761797993
1972    2   17.200476457399
1972    3   17.2926436045271
1972    4   17.3900277599829
1972    5   17.5987080931028
1972    6   17.6334881486229
1972    7   17.7030482596626
1972    8   17.7204382874227

A primeira linha está contida nas tabelas. Os arquivos são de texto simples (* .txt) com um separador "tab". A coluna ID é uma fictícia que eu gostaria de me livrar dela! Na minha saída desejada, os números (1,2,3, ...) na coluna DDD devem caber no dia dos anos correspondentes.

Alguém tem alguma idéia sobre como fazer isso (usando o bash)? Obrigado!

    
por steve 14.08.2015 / 12:04

4 respostas

2

Usando awk para análise e date para formatar a data, o que mais ;)

awk 'BEGIN {printf "%s\t%s\t%s\n","YYYY","DDD","sim"} NR != 1 {system("date -d \""$2"\" +\"%Y\t%-d\t"$3"\"")}' your_file

Para mostrar o dia do ano (usando %j em vez de %d ou melhor %-j em vez de %-d , o - evita 0 )

awk 'BEGIN {printf "%s\t%s\t%s\n","YYYY","DDD","sim"} NR != 1 {system("date -d \""$2"\" +\"%Y\t%-j\t"$3"\"")}' your_file

Exemplo

O arquivo de entrada

% cat foo
ID   date     DailyFlow
a 1972-01-01 17.0265761797993
b 1972-01-02 17.200476457399
c 1972-01-03 17.2926436045271
d 1972-01-04 17.3900277599829
e 1972-01-05 17.5987080931028
f 1972-01-06 17.6334881486229
g 1972-01-07 17.7030482596626
h 1972-02-01 17.7030482596626
i 1972-02-02 17.7030482596626

A saída (com o dia do mês)

% awk 'BEGIN {printf "%s\t%s\t%s\n","YYYY","DDD","sim"} NR != 1 {system("date -d \""$2"\" +\"%Y\t%-d\t"$3"\"")}' foo
YYYY    DDD sim
1972    1   17.0265761797993
1972    2   17.200476457399
1972    3   17.2926436045271
1972    4   17.3900277599829
1972    5   17.5987080931028
1972    6   17.6334881486229
1972    7   17.7030482596626
1972    1   17.7030482596626
1972    2   17.7030482596626

A saída (com o dia do ano)

% awk 'BEGIN {printf "%s\t%s\t%s\n","YYYY","DDD","sim"} NR != 1 {system("date -d \""$2"\" +\"%Y\t%-j\t"$3"\"")}' foo
YYYY    DDD sim
1972    1   17.0265761797993
1972    2   17.200476457399
1972    3   17.2926436045271
1972    4   17.3900277599829
1972    5   17.5987080931028
1972    6   17.6334881486229
1972    7   17.7030482596626
1972    32  17.7030482596626
1972    33  17.7030482596626
    
por A.B. 14.08.2015 / 14:25
7

Isso teria sido um trabalho para awk , mas a substituição na segunda coluna teria exigido gensub e, portanto, gawk , que não é instalado por padrão, então eu terminei com uma solução sed :

sed -i.bak 's/[^\t]*\t\([^-]*\)-[0-9][0-9]-[0-9]\([0-9]\)[^\t]*\t\([^\t]*\)/\t\t/' infile

Ou, encurtado usando EREs (graças ao user1598390):

sed -E -i.bak 's/.*([0-9]{4})-[0-9]{2}-([0-9]{2})(.*)/\t/' infile
  • -i.bak : processa o arquivo no lugar, fazendo o backup do arquivo original em infile.bak

% de colapso do comandosed:

  • s : afirma para executar uma substituição;
  • / : inicia o padrão
  • [^\t]* : corresponde a qualquer número de qualquer caractere que não seja \t ;
  • \t : corresponde a um caractere \t
  • \( : inicia o primeiro grupo de captura
  • [^-]* : corresponde a qualquer número de qualquer caractere que não seja - ;
  • \) : pára o primeiro grupo de captura
  • - : corresponde a um caractere -
  • [0-9] : corresponde a qualquer dígito
  • [0-9] : corresponde a qualquer dígito
  • - : corresponde a um caractere -
  • [0-9] : corresponde a qualquer dígito
  • \( : inicia o segundo grupo de captura
  • [0-9] : corresponde a qualquer dígito
  • \) : pára o segundo grupo de captura
  • [^\t]* : corresponde a qualquer número de qualquer caractere que não seja \t ;
  • \t : corresponde a um caractere \t
  • \( : inicia o terceiro grupo de captura
  • [^\t]* : corresponde a qualquer número de qualquer caractere que não seja \t ;
  • \) : pára o terceiro grupo de captura
  • / : interrompe o padrão / inicia a sequência de substituição
  • : backreference substituído pelo primeiro grupo de captura
  • : backreference substituído pelo segundo grupo de captura
  • : backreference substituído pelo terceiro grupo de captura
  • / : interrompe a string de substituição / inicia os modificadores

Saída para o arquivo de amostra:

user@debian ~/tmp % cat infile 
a   1972-01-01  17.0265761797993
b   1972-01-02  17.200476457399
c   1972-01-03  17.2926436045271
d   1972-01-04  17.3900277599829
e   1972-01-05  17.5987080931028
f   1972-01-06  17.6334881486229
g   1972-01-07  17.7030482596626
user@debian ~/tmp % sed 's/[^\t]*\t\([^-]*\)-[0-9][0-9]-[0-9]\([0-9]\)[^\t]*\t\([^\t]*\)/\t\t/' infile
1972    1   17.0265761797993
1972    2   17.200476457399
1972    3   17.2926436045271
1972    4   17.3900277599829
1972    5   17.5987080931028
1972    6   17.6334881486229
1972    7   17.7030482596626
    
por kos 14.08.2015 / 13:01
1

Use awk :

awk 'BEGIN{print "YYYY\tDDD\tsim"} NR!=1{printf "%s\t%s\t%s\n",substr($2,0,5),$1,$3}' file

Explicação

  1. A parte BEGIN{} formata a linha de cabeçalho.
  2. NR!=1 omite a linha de cabeçalho do seu arquivo
  3. printf() formata a saída
  4. substr($2,0,5) remove o dia e o mês a partir da data

A saída parece:

YYYY    DDD     sim
1972    1       17.0265761797993
1972    2       17.200476457399
1972    3       17.2926436045271
1972    4       17.3900277599829
1972    5       17.5987080931028
1972    6       17.6334881486229
1972    7       17.7030482596626
    
por chaos 14.08.2015 / 13:30
1

Usando apenas bash :

#!/bin/bash
shopt -s extglob
printf "YYYY\tDDD\tsim\n"
while IFS=$'\t' read -r first second third; do
    day="$(date --date="$second" '+%j')"
    printf "%s\t%s\t%s\n" "${second%%-*}" "${day##*(0)}" "${third}"
done < <(tail -n +2 foo.txt)
  • Estamos lendo cada linha do arquivo de entrada a partir da segunda linha e colocando as partes separadas da guia como variável first , second e third sucessivamente

  • Em seguida, estamos usando a expansão do parâmetro bash para obter nosso padrão de saída desejado. Leia sobre a expansão de parâmetros do documento GNU .

  • extglob é usado para remover os zeros preenchidos de dias.

Exemplo:

Entrada:

ID  date        DailyFlow
a   1972-01-01  17.0265761797993
b   1972-01-02  17.200476457399
c   1972-01-03  17.2926436045271
d   1972-01-04  17.3900277599829
e   1972-01-05  17.5987080931028
f   1972-01-06  17.6334881486229
g   1972-01-07  17.7030482596626
h   1972-02-01  17.7030482596626
i   1972-02-02  17.7030482596626

Saída:

YYYY    DDD   sim
1972    1     17.0265761797993
1972    2     17.200476457399
1972    3     17.2926436045271
1972    4     17.3900277599829
1972    5     17.5987080931028
1972    6     17.6334881486229
1972    7     17.7030482596626
1972    32    17.7030482596626
1972    33    17.7030482596626
    
por heemayl 14.08.2015 / 22:38