Pergunta

Eu tenho um arquivo delimitado por vírgula "myfile.csv" onde a quinta coluna é um carimbo de data/hora.(mm/dd/aaaa hh:mm). Preciso listar todas as linhas que contêm datas duplicadas (há muitas)

Estou usando um shell bash via cygwin para WinXP

$ cut -d, -f 5 myfile.csv | sort | uniq -d 

retorna corretamente uma lista das datas duplicadas

01/01/2005 00:22
01/01/2005 00:37
[snip]    
02/29/2009 23:54

Mas não consigo descobrir como alimentar isso no grep para me fornecer todas as linhas.Obviamente, não posso usar xargs direto, pois a saída contém espaços.Eu pensei que poderia fazer uniq -z -d mas por alguma razão, combinar esses sinalizadores faz com que o uniq (aparentemente) não retorne nada.

Então, dado que

 $ cut -d, -f 5 myfile.csv | sort | uniq -d -z | xargs -0 -I {} grep '{}' myfile.csv

não funciona...O que posso fazer?

Eu sei que eu poderia fazer isso em perl ou outra linguagem de script ...mas minha natureza teimosa insiste que eu deveria ser capaz de fazer isso em bash usando ferramentas de linha de comando padrão como sort, uniq, find, grep, cut, etc.

Ensine-me, oh gurus.Como posso obter a lista de linhas necessárias usando ferramentas CLI típicas?

Foi útil?

Solução

  1. sort -k5,5 fará a classificação nos campos e evitará o corte;
  2. uniq -f 4 irá ignorar os primeiros 4 campos do uniq;
  3. Além disso, um -D no uniq fornecerá todas as linhas repetidas (vs -d, que fornecerá apenas uma);
  4. mas o uniq esperará delimitado por tabulações em vez de csv, então tr ' ' ',' para corrigir isso.

O problema é se você tiver campos após o número 5 diferentes.Suas datas têm todas a mesma duração?Você pode adicionar -w 16 (para incluir hora) ou -w 10 (apenas para datas) ao uniq.

Então:

tr '\t' ',' < myfile.csv | sort -k5,5 | uniq -f 4 -D -w 16

Outras dicas

O -z opção de uniq precisa que a entrada seja separada por NUL.Você pode filtrar a saída de cut através:

tr '\n' '\000'

Para obter zero linhas separadas.Então sort, uniq e xargs tenho opções para lidar com isso.Tente algo como:

cut -d, -f 5 myfile.csv | tr '\n' '\000' | sort -z | uniq -d -z | xargs -0 -I {} grep '{}' myfile.csv

Editar:a posição do tr no cano estava errado.

Você pode dizer ao xargs para usar cada linha como argumento completo usando a opção -d.Tentar:

cut -d, -f 5 myfile.csv | sort | uniq -d | xargs -d '\n' -I '{}' grep '{}' myfile.csv

Tente escapar dos espaços com sed:

echo 01/01/2005 00:37 | sed 's/ /\\ /g'
cut -d, -f 5 myfile.csv | sort | uniq -d | sed 's/ /\\ /g' | xargs -I '{}' grep '{}' myfile.csv

(Outra maneira seria ler as linhas de data duplicadas em um array IFS=$' ' e iterar sobre ele em um loop for.)

Este é um bom candidato para awk:

BEGIN { FS="," }
{ split($5,A," "); date[A[0]] = date[A[0]] " " NR }
END { for (i in date) print i ":" date[i] }
  1. Defina o separador de campo como ',' (CSV).
  2. Divida o quinto campo no espaço, cole o resultado em A.
  3. Concatene o número da linha à lista do que já armazenamos para aquela data.
  4. Imprima os números das linhas para cada data.
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top