Empilhar dados de vários arquivos delimitados em um, com colunas variáveis

2

Sou novo em scripts. Fiquei impressionado com um problema de mesclagem de arquivos no Unix. Estava procurando por alguma direção e topou com este site. Vi muitos posts e respostas incríveis, mas não consegui encontrar uma solução para meu problema. Aprecio muito qualquer ajuda ..

Eu tenho três arquivos csv - > Apex_10_Latest.csv, Apex_20_Latest.csv, Apex_30_Latest.csv. O número de colunas varia nesses três arquivos. Normalmente, o arquivo mais recente, com base na numeração, pode ter algumas novas colunas anexadas ao final. Então eu quero pegar o último cabeçalho e empilhar os dados de todos os 3 arquivos em um novo arquivo Apex.csv. Ao empilhar os dados do arquivo mais antigo, que pode ter menos colunas do que o arquivo mais recente, quero que os dados sejam preenchidos como nulos com os delimitadores apropriados.

Além disso, isso deve ser feito recursivamente para um conjunto múltiplo de arquivos (3 cada), todos na mesma pasta. - Apex_10_Latest.csv, Apex_20_Latest.csv, Apex_30_Latest.csv - mesclado no Apex.csv - Code_10_Latest.csv, Code_20_Latest.csv, Code_30_Latest.csv - mesclado em Code.csv - Trans_10_Latest.csv, Trans_20_Latest.csv, Trans_30_Latest.csv - mesclados em Trans.csv

A seguir, o formato dos arquivos de origem e do arquivo de destino esperado ... FONTE DE ARQUIVOS:

  • Apex_30_Latest.csv:
    A, B, C, D
    1,2,3,4
    2,3,4,5
    3,4,5,6

  • Apex_20_Latest.csv:
    A, B, C
    4,5,6

    5,6,7
    6,7,8

  • Apex_10_Latest.csv:
    A, B
    7,8
    8,9
    9,10

ARQUIVO ALVO ESPERADO:

  • Apex.csv
    A, B, C, D
    1,2,3,4
    2,3,4,5
    3,4,5,6
    4,5,6 ,
    5,6,7 ,
    6,7,8 ,
    7,8 ,
    8,9 ,
    9,10 ,

Obrigado ...

    
por wamshi 23.10.2015 / 04:26

3 respostas

0

  cat $(ls -1 Apex_*_Latest.csv | sort -nr -k2 -t'_') | awk -F"," '{
           if (NR==1){
                nfm=NF};
           for (i=1;i<=nfm;i++) {
                printf $i","};
           print ""}' >Apex.csv

Você pode reverter sort nomes de arquivos com base no segundo campo (30,20,10 ..) e cat dos arquivos, de modo que as linhas com o maior número de colunas apareçam primeiro.

Então, com awk você pode obter o maior número de colunas NF da primeira linha NR          if (NR==1){nfm=NF}

Em seguida, execute um loop for até i (número da coluna) maior ou igual a nfm para imprimir valores no campo sem i seguidos de ','. se não houver valor para o campo i th (acontecer quando as colunas forem menores que os arquivos mais recentes), ele imprimirá apenas , .

    
por 23.10.2015 / 11:02
0

Eu acho que a resposta anterior é a melhor, eu só mostro uma abordagem diferente, já que não uso o awk há anos, já que perl e python se tornaram grandes. Eu acho que o awk está bem, é só que uma mistura de shell, sed, python e / ou perl se adequou melhor ao meu trabalho.

No entanto, neste caso, acho que qualquer um pode ver que a solução awk é mais sucinta e mais fácil de ler. Venha para pensar sobre isso, eu acho que ouvi o awk referido como a planilha de linha de comando, ou algo parecido. : -)

Com base na postagem original, optei por permitir que o comando ls classificasse os nomes dos arquivos pelo tempo de modificação do arquivo, em vez de confiar no formato do nome do arquivo. Seis de um, meia dúzia do outro.

Então, para fins de comparação, aqui está uma versão da solução eficiente, portátil, modular (?!), pura:

    #!/bin/sh

    get_commas() {
        sed 's/[^,]//g; 1q' "$@"
    }

    get_extra_commas() {
        local maxcommas="$1"
        local file="$2"
        local new_commas=$(get_commas "$file")
        local extra_commas=""
        while [ "${new_commas}${extra_commas}" != "${maxcommas}" ]
        do
            extra_commas=",$extra_commas"
        done
        echo "$extra_commas"
    }

    unset header
    ls -t Apex*.csv |
    while read filename
    do
        if [ -z "$header" ]
        then
            header="$(sed 1q "$filename")"
            commas=$(echo "$header" | get_commas)
            echo "$header"
        fi
        extra_commas=$(get_extra_commas $commas "$filename")
        sed "1d; s/\$/$extra_commas/" "$filename"
    done
    
por 25.10.2015 / 00:25
0

Aqui está uma resposta implementada em Miller :

$ cat rect.mlr
for (k,v in $*) {
  @fields[k] = v; # retain already-seen field names
}
for (k,v in @fields) {
  if (isabsent($[k])) {
    $[k] = "";
  }
}

$ mlr --csvlite put -f rect.mlr Apex_30_Latest.csv Apex_20_Latest.csv Apex_10_Latest.csv
A,B,C,D
1,2,3,4
2,3,4,5
3,4,5,6
4,5,6,
5,6,7,
6,7,8,
7,8,,
8,9,,
9,10,,

Como Miller lida intrinsecamente com colunas nomeadas, o gerenciamento da linha de cabeçalho se torna mais simples.

    
por 12.11.2016 / 03:16