Concatena vários arquivos sem cabeçalho

2

Eu tenho vários diretórios ("amazon", "niger", ...), nos quais tenho vários subdiretórios ("gfdl", "hadgem", ...), nos quais também tenho vários subdiretórios ("rcp8p5", "rcp4p5", ...). Nos últimos subdiretórios eu sempre tenho duas pastas ("histórico", "projetadas") que contêm milhares de tabelas com o mesmo quadro. Portanto, gostaria de concatenar essas tabelas (presentes nas duas pastas dos últimos subdiretórios) para ter apenas uma tabela grande com apenas um cabeçalho e não um cabeçalho sempre que uma tabela fosse concatenada. Alguém sabe como fazer isso?

Atualmente, estou usando a seguinte estrutura de loop:

#!/bin/bash
# usage:cat_dat dirname

data_dir=/scratch/01/stevens/climate_scenario/river

for river in tagus
  do
   for gcm in gfdl-esm2m hadgem2-es
     do
      for scenario in rcp8p5 rcp4p5 rcp6p0 rcp2p6
        do
          find "${data_dir}/${river}/${gcm}/${scenario}" name \*.dat -exec cat {} + >> "${data_dir}/${river}/${gcm}/${scenario}.dat"
      done
   done
done

mas não consigo me livrar do cabeçalho com isso! Qualquer ajuda é muito apreciada! Obrigado!

    
por steve 03.08.2015 / 15:09

2 respostas

2

Usando awk em uma única pasta

awk 'NR==1 {header=$_} FNR==1 && NR!=1 { $_ ~ $header getline; } {print}' *.dat > out

find e awk se você precisar de todos os arquivos na pasta atual e nas subpastas. Você pode substituir . pela pasta desejada.

find . -type f -name "*.dat" -print0 | \
    xargs -0 awk 'NR==1 {header=$_} FNR==1 && NR!=1 { $_ ~ $header getline; } {print}' > out

ou, como getline é ruim (thx @ fedorqui )

find . -type f -name "*.dat" -exec awk 'NR==1 || FNR!=1' {} + ;

Exemplo

% cat foo1.dat 
a   b   c
1   2   3

% cat foo2.dat
a   b   c
4   5   6

% awk 'NR==1 {header=$_} FNR==1 && NR!=1 { $_ ~ $header getline; } {print}' *.dat > out

% cat out 
a   b   c
1   2   3
4   5   6
    
por A.B. 03.08.2015 / 15:22
2

Você pode usar um loop while que é alimentado por uma find através da substituição do processo :

d=0
while IFS= read -r file
do
   [ "$d" -ge 1 ] && tail -n +2 "$file" || cat "$file"
   (( d ++ ))
done < <(find "/dir/folder" name *.dat)

Por isso, irá executar um cat no primeiro jogo e tail -n +2 no restante.

Como alternativa, se você tiver todos os arquivos no mesmo diretório, poderá dizer:

awk 'FNR>1 || NR==1' files*

Isso corresponderá a tudo, exceto ao caso em que FNR==1 e NR>1 , ou seja, tudo, exceto o cabeçalho dos arquivos após o primeiro. Por quê? Porque NR contém o número de linhas sendo lidas no geral, enquanto FNR contém o número de linhas do arquivo atual sendo lido.

    
por fedorqui 03.08.2015 / 15:22