Remoção de linhas sem mais ou menos que 'N' campos?

7

Estou trabalhando no mac com sed, perl, awk, bash ..

Eu tenho um arquivo de texto grande (10 GB) que possui 13 campos (colunas) de dados delimitados por TAB . Infelizmente, algumas dessas linhas têm TABs alheio, por isso quero excluir toda a linha em que temos campos TABs extras e, portanto, campos desiguais. (Eu não me importo de descartar as linhas na sua totalidade)

O que tenho atualmente grava o número de campos em outro arquivo.

awk -F'\t' '{print NF}' infile  > fieldCount

head fieldCount
13
13
10
13
13
13
14
13
13
13

Eu gostaria de construir um script curto que remova qualquer linha com mais (ou menos) que 13 campos apropriados (do arquivo original).

  1. a velocidade é útil, pois tenho que fazer isso em vários arquivos
  2. fazer isso em uma varredura seria legal
  3. Atualmente, estou migrando o arquivo fieldCount para o Python, tentando carregar linha por linha.

EDITAR:

vaild (13 colunas)

a       b       c       d       e       f       g       h       i       j       k       l       m

inválido (14 colunas)

a       b       c       d       e       f       g       h       i       j       k       l       m       n
    
por T. Scharf 22.08.2014 / 19:49

3 respostas

10

Você quase já o tem:

awk -F'\t' 'NF==13 {print}' infile  > newfile

E, se você estiver em um desses sistemas onde você é cobrado pelo toque de tecla (:) você pode encurtar isso para

awk -F'\t' 'NF==13' infile  > newfile

Para fazer vários arquivos em uma varredura, e realmente mudar os arquivos (e não apenas criar newfiles), identificar um nome de arquivo que não esteja em uso (por exemplo, scharf ), e faça um loop, assim:

for f in list
do
    awk -F'\t' 'NF==13 {print}' "$f" > scharf  &&  mv -f -- scharf "$f"
done

O list pode ser um ou mais nomes de arquivo e / ou padrões de expansão de nome de arquivo curinga; por exemplo,

for f in blue.data green.data *.dat orange.data red.data /ultra/violet.dat

O comando mv sobrescreve o arquivo de entrada (por exemplo, blue.data ) com o arquivo scharf temporário (que tem apenas as linhas do arquivo de entrada com 13 campos). (Certifique-se de que isso é o que você quer fazer e tenha cuidado. Para estar seguro, você provavelmente deve fazer backup de seus dados primeiro.) O -f informa mv para sobrescrever o arquivo de entrada, mesmo que já exista. O -- protege você contra a estranheza se algum dos seus arquivos tiver um nome começando com - .

    
por 22.08.2014 / 19:57
2

Como esse é um arquivo grande, pode valer a pena usar uma ferramenta um pouco mais complexa para obter um ganho de desempenho. Normalmente, as ferramentas especializadas são mais rápidas que as ferramentas generalistas. Por exemplo, resolver o mesmo problema com cut tende a ser mais rápido que grep , que tende a ser mais rápido que sed , que tende a ser mais rápido que awk (o outro lado é que ferramentas posteriores podem fazer coisas que anteriormente os que não podem).

Você deseja remover linhas com 13 caracteres de tabulação ou mais, portanto:

LC_ALL=C grep -Ev '(␉.*){13}'

ou talvez (não espero uma diferença de desempenho mensurável)

LC_ALL=C grep -Ev '(␉.*){12}␉'

onde é um caractere de tabulação literal. Definir a localidade como C não é necessário, mas acelera algumas versões do GNU grep em comparação com as localidades multibyte.

    
por 23.08.2014 / 00:54
1

com perl :

perl -F'\t' -anle 'print if @F == 13' file

para editar no local, adicione -i option:

perl -i.bak -F'\t' -anle 'print if @F == 13' file
    
por 22.08.2014 / 20:01