Como concatenar um número variável de csv, removendo suas linhas de cabeçalho?

0

Eu tenho um diretório com várias centenas de arquivos csv cujos nomes de arquivos começam com dois dígitos {01..84} . Várias centenas > > 84, então obviamente alguns nomes de arquivos começam com o mesmo prefixo. Desejo concatenar os arquivos cujos nomes de arquivos começam com o mesmo prefixo. Aqui está o que eu tenho:

#!/bin/bash
for i in {01..84}; do
        #declare array to store files with same prefix
        declare -a files=()
        echo "Processing $i"
        for j in 'ls $i*.csv'; do
                #add files with same prefix to array
                files=("${files[@]}" "$j")
        done    
        #cat first file including header with the rest of the files without the headers 
        cat < ${files[@]:0:1} <(tail -n+2 ${files[@]:1}) > "$i".csv
done 

Até aí tudo bem ... apenas, ele para em $i = 22 na metade (erro repetível) e polui os arquivos de saída com linhas em branco e cabeçalhos como "== > 19XXX.csv < ; == "(sem aspas).

  1. O que devo alterar no código para obter apenas um arquivo csv limpo e limpo para cada prefixo sem que o script falhe?

  2. Existe algum utilitário pré-compilado que eu possa chamar para fazer isso mais rápido e mais fácil?

por Escher 12.01.2015 / 11:53

3 respostas

0

Solução de código de trabalho para quem acabou de vir aqui para copiar e colar com base no wurtel:

#!/bin/bash
for i in {01..84}; do
    #declare array to store files with same prefix
    declare -a files=()
    echo "Processing $i"
    for j in 'ls $i*.csv'; do
        #add files with same prefix to array
        files=("${files[@]}" "$j")
    done
    #cat first file including header with the rest of the files without the headers
    if [ ${#files[@]} -gt 1 ]; then
        cat <(cat ${files[@]:0:1}) <(tail -q -n+2 ${files[@]:1}) > "$i".csv
    else
        cat <(cat ${files[@]:0:1}) > "$i".csv
    fi
done

Stéphane Chazelas usando o awk. Muito mais limpo.

#!/bin/bash
for i in {01..84}; do
        echo "processing $i"
        awk 'NR==FNR||FNR>1' $i?*.csv >> "$i".csv
done
    
por 13.02.2015 / 00:51
3
#!/bin/bash
for i in {01..84}; do
    x=$(printf '%02d' $i)
    set -- $x?*.csv
    if [ -f "$1" ]; then
        cp "$1" $i.csv
        shift
        if [ -f "$1" ]; then
            tail -q -n +2 "$@" >> $x.csv
        fi
    fi
done

Para cada prefixo, ele define a lista de arquivos com esse prefixo como argumentos para que você possa usar $1 para acessar o primeiro, etc.

Se $1 for um arquivo (para capturar o caso em que não há arquivos com o prefixo especificado), copie esse arquivo para prefix.csv. Em seguida, verifique se havia mais de um arquivo com esse prefixo, desmarcando o primeiro arquivo e verificando o próximo também é um arquivo. Em caso afirmativo, pule a linha de cabeçalho de cada arquivo através do comando tail e anexe-o ao prefixo.csv.

A opção -q para tail é para suprimir a linha de cabeçalho tail em si irá adicionar se mais de um arquivo for passado na lista de argumentos; este é o lugar de onde suas linhas ==> 19XXX.csv <== estavam vindo.

Provavelmente apenas a opção -q é necessária em sua solução, mas acho que é muito complicado, exigindo que bash armazene a saída do comando tail , etc., que pode ser a causa do script parar (travar? prematuramente.

EDIT: adicionado x=$(printf '%02d' $i) como {01..84} expande para 1 2 3 ... sem zeros iniciais.

    
por 12.01.2015 / 12:16
1
#!/bin/sh
for i in {01..84}
do
  cat $i*.csv > $i.csv-concat
  rm $i*.csv
  mv $i.csv-concat $i.csv
done

não se esqueça do gato, é uma ferramenta de concatenação, cauda também pode fazer o trabalho e remover o cabeçalho.

#!/bin/sh
pushd [workdir]
for i in {01..84}
do
  echo $i*.csv | xargs -n 1 tail -n+2 > $i.csv-concat
  rm $i*.csv
  mv $i.csv-concat $i.csv
done
popd
    
por 12.01.2015 / 17:30