Organize as entradas como uma planilha (csv) usando o awk

3

Eu tenho informações para entradas (N = 1000) salvas em um computador em um arquivo de texto delimitado / por entrada (cada entrada tem um arquivo de texto). As informações registradas no mesmo formato que o seguinte:

============
NAME: Matty Nigan
Age: 65 
Sex: M
Weight: XX
TIME: 12:31:25
Home address: XXXXX
Phone number: XXX XXX XXXX
============

Eu quero coletar e organizar todos os dados dessas entradas (N = 1000) da seguinte maneira:

NAME         AGE   SEX   Weight HOME Phone
===========
Matty Nigan  65     M    XX      XX    XX
..........
..........
..........
..........

Eu tentei este código:

#!/bin/bash
source=path to the folder where the entries files are.
for i in $(cat file.txt); do # file.txt is including all the delimited text files names

 awk '
 /Name:/ {name=$2}
 /Age:/ {age=$2 }
 /Sex:/ {sex=$2}
 /Home: / {home=$3}
 /Phone:/ {phone=$3}
 BEGIN { FS=":"; print "name\t\tage\t\tsex\t\thome\t\tphone:\n---------"; }       
 {print $2,"\t\t",$3,"\t\t",$4,"\t\t",$6,"\t\t",$7;}END{ print "---------\nFile Complete" }'
' ${source}/${i}| sh > outdata.csv
done

Infelizmente isso não funcionou! Eu não sei o que estou fazendo errado. Qualquer ajuda é muito apreciada.

    
por steve 08.08.2015 / 20:25

3 respostas

2
awk '
BEGIN {
    fmt="%-15s%-10s%-10s%-10s%-10s%-10s\n"
    printf fmt,"Name","Age","Sex","Weight","Home","Phone"
    print "---------"
}

{
    v=$0
    sub(/[^:]*: /, "", v)
    a[$1]=v
}

/Phone/ {
    printf fmt,a["NAME:"],a["Age:"],a["Sex:"],a["Weight:"],a["Home"],a["Phone"]
    delete a
}

END{ 
    print "---------\nFile Complete" 
}' file*

O uso de guias duplas entre colunas é problemático. Se houver, digamos, nomes longos e nomes curtos, as colunas podem confundir e acabar nos lugares exatamente errados. No acima, eu formatei colunas com larguras dadas. Você pode precisar ajustar as larguras para obter melhores resultados.

Observe que FS=":" também pode causar problemas. Campos podem conter dois pontos e isso confundiria a contagem. Isso pode ser evitado quebrando as informações no primeiro cólon como as instruções abaixo. Essas instruções capturam todas as informações do arquivo em uma matriz a :

v=$0
sub(/[^:]*: /, "", v)
a[$1]=v

O primeiro campo é a chave. Tudo depois do primeiro espaço de dois pontos é o valor.

Um único comando awk pode processar muitos arquivos. Como acima, todos os arquivos correspondentes ao glob file* são processados. Substitua isso por qualquer glob que corresponda aos seus arquivos de dados.

O acima processa uma pessoa de cada vez. Isso significa que esse código não requer memória grande e, consequentemente, é adequado para grandes conjuntos de dados.

Saída de amostra

$ bash script.sh
Name           Age       Sex       Weight    Home      Phone     
---------
Matty Nigan    65        M         XX        XXXXX     XXX XXX XXXX
---------
File Complete
    
por 08.08.2015 / 21:57
0

Tente usar um awk construído como abaixo. Cria um array com os detalhes e imprime o lote no final.

awk -F: '
/^NAME/{name[c]=$2}
/^Age:/{age[c]=$2}
/^Sex:/{sex[c]=$2}
/^Weight:/{weight[c]=$2}
/^Home address:/{home[c]=$2}
/^Phone number:/{phone[c]=$2;c++}
END {
 print "NAME         AGE   SEX   Weight HOME Phone"
 print "==========="
 for(x in name) {
  printf "%-10s %3d    %s      %s %s %s\n",
    substr(name[x],2),
    age[x],
    sex[x],
    weight[x],
    home[x],
    phone[x]
 }
}'
    
por 08.08.2015 / 21:41
0

Além disso, parece que a instrução que começa com "{print $ 2 ..." será executada para cada registro de entrada. Melhor incluir a impressão nas chaves após o / PHONE: / selector. Além disso, se eu estivesse fazendo isso, colocaria a parte BEGIN na cabeça do programa, em vez de incorporá-la mais abaixo como está.

Como observado no comentário anterior, a impressão deve mencionar nome, idade, sexo, etc., em vez de US $ 2, US $ 3, US $ 4, etc.

Eu acredito que o / PHONE: / {phone = $ 3} lhe dará problemas. Como mostram os dados da amostra, os três grupos de dígitos do número de telefone, separados por espaços, aparecerão como $ 3 $ 4 $ 5. Assim, para reunir todo o número de telefone, / PHONE: / {phone = $ 3 "-" $ 4 "-" $ 5} seria mais apropriado.

    
por 08.08.2015 / 21:54