Question

J'ai un fichier séparé par des virgules " monfichier.csv " où la 5ème colonne est un timbre date / heure. (mm / jj / aaaa hh: mm). Je dois répertorier toutes les lignes contenant des dates en double (il y en a beaucoup)

J'utilise un shell bash via cygwin pour WinXP

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

renvoie correctement une liste des dates en double

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

Mais je ne peux pas comprendre comment alimenter Grep avec toutes les lignes. Évidemment, je ne peux pas utiliser xargs directement, car la sortie contient des espaces. Je pensais pouvoir faire uniq -z -d , mais pour une raison quelconque, la combinaison de ces indicateurs provoque (apparemment) que rien ne retourne uniq.

Donc, étant donné que

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

ne fonctionne pas ... que puis-je faire?

Je sais que je pourrais le faire avec perl ou un autre langage de script ... mais ma nature obstinée insiste sur le fait que je devrais pouvoir le faire dans bash en utilisant la norme des outils en ligne de commande tels que tri , uniq , find , grep , coupé , etc.

Apprends-moi, oh bash gourous. Comment puis-je obtenir la liste des lignes dont j'ai besoin à l'aide des outils cli classiques?

Était-ce utile?

La solution

  1. sort -k5,5 fera le tri sur les champs et évitera la coupure;
  2. uniq -f 4 ignorera les 4 premiers champs de l’uniq;
  3. De plus, un -D sur l'uniq vous donnera toutes les lignes répétées (vs -d, ce qui ne vous en donne qu'une);
  4. mais uniq attendra que les fichiers soient séparés par des tabulations au lieu de csv, donc tr '\ t' ',' pour résoudre ce problème.

Le problème est que vous avez des champs après le n ° 5 différents. Vos dates sont-elles toutes de la même longueur? Vous pourrez peut-être ajouter -w 16 (pour inclure l'heure) ou -w 10 (pour les dates uniquement) à l'uniq.

Donc:

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

Autres conseils

L'option -z de uniq nécessite que l'entrée soit séparée de NUL. Vous pouvez filtrer la sortie de couper à travers:

tr '\n' '\000'

Pour obtenir zéro ligne séparée. Ensuite, sort , uniq et xargs ont des options pour gérer cela. Essayez quelque chose comme:

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

Edit: la position de tr dans le tuyau était incorrecte.

Vous pouvez indiquer à xargs d'utiliser chaque ligne comme un argument complet à l'aide de l'option -d. Essayez:

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

Essayez d'échapper aux espaces avec 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

(Une autre solution consisterait à lire les lignes de date en double dans un tableau IFS = $ '\ n' et à les parcourir dans une boucle for.)

C’est un bon candidat pour awk:

BEGIN { FS="," }
{ split($5,A," "); date[A[0]] = date[A[0]] " " NR }
END { for (i in date) print i ":" date[i] }
  1. Définissez le séparateur de champ sur ',' (CSV).
  2. Divisez le cinquième champ de l'espace, collez le résultat dans A.
  3. Concaténez le numéro de ligne à la liste de ce que nous avons déjà stocké pour cette date.
  4. Imprimez les numéros de ligne pour chaque date.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top