Rejoindre plusieurs champs dans des fichiers texte sur Unix
Comment puis-je le faire?
Fichier1 ressemble à ceci:
foo 1 scaf 3
bar 2 scaf 3.3
Fichier2 ressemble à ceci:
foo 1 scaf 4.5
foo 1 boo 2.3
bar 2 scaf 1.00
Ce que je veux faire est de trouver des lignes qui co-produisent dans Fichier1 et Fichier2
lorsque les champs 1,2, et 3 sont les mêmes.
Est-il un moyen de le faire?
source d'informationauteur neversaint
Vous devez vous connecter pour publier un commentaire.
vous pouvez essayer ce
sortie
Si vous souhaitez omettre rare lignes
sortie
La commande join est difficile à utiliser et ne rejoint sur une colonne
Une vaste expérimentation en plus de l'examen minutieux des pages de manuel indique que vous ne pouvez directement joindre plusieurs colonnes - et tous mes exemples de travail de rejoindre, curieusement, utiliser une seule colonne de jointure.
Par conséquent, toute solution exigera les colonnes-à-être-joint à être concaténées en une seule colonne, en quelque sorte. Le standard de la commande join exige également ses entrées à dans le bon ordre - il y a une remarque dans la GNU join (info coreutils joindre) à ce sujet pas toujours nécessitant des données triées:
Une façon possible de le faire avec ces fichiers est:
Cela crée un composite champ de tri au début, à l'aide de ':' pour séparer les sous-champs, puis trie le fichier - pour chacun des deux fichiers. La commande join rejoint ensuite sur les deux champs composites, mais imprime uniquement la non-composite (non-join) champs.
La sortie est:
L'échec des tentatives pour faire adhérer faire ce qu'il ne fera
rejoindre -1 1 -2 1 -1 2 -2 2 -1 3 -2 3 -o 1.1,1.2,1.3,1.4,2.4 fichier1 fichier2
Sur mac os X 10.6.3, cela donne:
C'est le rejoindre sur le champ 3 (uniquement) - ce qui n'est pas ce qui est voulu.
Vous avez besoin pour vous assurer que les fichiers d'entrée sont dans le bon ordre.
Ici est la corriger réponse (en termes de l'utilisation de la norme GNU coreutils outils, et ne pas écrire un script personnalisé dans perl/awk vous le nom).
OK, comment ça fonctionne:
Tout d'abord, nous allons utiliser un outil formidable
join
qui peut fusionner deux lignes.join
a deux exigences:Nous avons besoin pour générer clés dans les fichiers d'entrée et pour cela, nous utilisons un simple
awk
script:Vous le voyez, nous avons ajouté la 1ère colonne avec certaines clés comme "foo-1-conseil suprême des forces armées".
Nous faisons la même chose avec fichier2.
BTW.
<file awk
, est simplement envie d'écrireawk file
, oucat file | awk
.Nous devrions aussi sorte nos fichiers par clé, dans notre cas, c'est la colonne 1, nous avons donc ajouter
à la fin de la commande de la
| sort -k1,1
(sorte par le texte à partir de la colonne 1 à la colonne 1)À ce stade, nous pourrions nous contenter de générer des fichiers fichier1.avec.clé et fichier2.avec.clé et se joindre à eux,
mais supposons que ces fichiers sont énormes, nous ne voulons pas de les copier sur le système de fichiers. Au lieu de cela, nous pouvons utiliser ce qu'on appelle
bash
processus de substitution afin de générer une sortie en tube nommé (cela permettra d'éviter toutinutile intermédiaire de création du fichier). Pour plus d'informations s'il vous plaît lire le lien fourni.
Notre objectif, la syntaxe est:
join <( some command ) <(some other command)
La dernière chose à expliquer fantaisie rejoindre arguments:
-j1 -o1.2,1.3,1.4,1.5,2.5
-j1
- inscrivez-clé dans la 1ère colonne (dans les deux fichiers)-o
- sortie uniquement les champs1.2
(1er fichier champ2),1.3
(1ère colonne du fichier 3), etc.De cette façon, nous avons rejoint les lignes, mais
join
sorties uniquement les colonnes nécessaires.Les leçons tirées de ce poste devrait être:
Il est probablement plus facile de combiner les trois premiers champs avec awk:
Ensuite, vous pouvez utiliser
join
normalement sur "zone 1"Ici est une façon de le faire en Perl:
Comment sur:
C'est en supposant que vous n'êtes pas trop inquiet à propos de l'espace blanc entre les champs (en d'autres termes, trois onglets et un espace n'est pas différent d'un espace et 7 onglets). C'est généralement le cas lorsque l'on parle de champs dans un fichier texte.
Ce qu'il fait est de sortie les deux fichiers, dépouillant le dernier champ (puisque vous n'avez pas de soins à ce sujet en termes de comparaisons). Il les trie que des lignes adjacentes sont ensuite uniquifies (remplace chaque groupe de côté les lignes identiques avec une copie et un nombre).
Puis, il se débarrasse de tous ceux qui ont un compte (pas de doublons) et imprime chaque avec le comte dépouillé. Que vous donne votre "clés" pour le dédoublement des lignes et vous pouvez alors utiliser un autre awk itération pour localiser ces touches dans les fichiers si vous le souhaitez.
Ce ne fonctionner comme prévu si deux clés identiques sont dans un seul fichier car les fichiers sont combinés dès le début. En d'autres termes, si vous avez des doubles de clés dans
file1
mais pas dansfile2
qui va être un faux positif.Alors, la seule véritable solution à laquelle je pense est une solution qui vérifie
file2
pour chaque ligne dansfile1
bien que je suis sûr que d'autres peuvent venir avec plus sage des solutions.Et, pour ceux qui aiment un peu de sado-masochisme, voici l'adresse ci-dessus de ne pas-trop-solution efficace:
Cela on construit un fichier script distinct pour faire le travail. Pour chaque ligne dans
file1
il crée une ligne dans le script de rechercher que dansfile2
. Si vous voulez voir comment cela fonctionne, il suffit de jeter un coup d'oeil àxx99
avant de le supprimer.Et, dans celui-ci, les espaces ne importe donc ne soyez pas surpris si il ne fonctionne pas pour les lignes où les espaces sont différents entre
file1
etfile2
(même si, comme la plupart des "affreux" scripts, qui peut être fixé avec juste un maillon de plus dans le pipeline). C'est plus ici qu'un exemple de l'horrible des choses que vous pouvez créer pour rapide n'dirty emplois.C'est pas ce que je ferais pour la production d'un code de qualité, mais c'est bien pour une fois, à condition de détruire toutes les preuves avant de Le Daily WTF constate à ce sujet 🙂
Méthode Simple (pas de awkrejoindresedou perl), en utilisant des outils logiciels
cut
grep
etsort
:De sortie (pas d'impression inégalée lignes):
Comment il fonctionne...
cut
fait une liste de toutes les lignes de la recherche.grep
's-f -
entrées de commutation les lignes decut
et de recherches Fichier1 et Fichier2 pour eux.sort
n'est pas nécessaire, mais ce qui rend les données plus faciles à lire.Condensé des résultats avec
datamash
:De sortie:
Si Fichier1 est énorme et est un peu redondante, l'ajout de
sort -u
devrait accélérer les choses:Un professeur que j'ai utilisé pour travailler avec a créé un ensemble de scripts perl qui peut effectuer un grand nombre de type base de données des opérations sur la colonne orientée à plat des fichiers texte. Il est appelé Fsdb. Il peut certainement le faire, et elle est particulièrement utile dans la recherche si ce n'est pas seulement un besoin (si vous n'êtes pas constamment écriture de scripts personnalisés).
À l'aide de
datamash
's effondrement opération, plus un peu de cosmétiquesort
ing ettr
ing:De sortie (lignes communes ont une 5ème champ, rare lignes):
Une solution similaire que celui de Jonathan Leffler offert.
Créer 2 temporaire triés fichiers avec un autre délimiteur qui a la correspondance des colonnes dans le premier champ.
Joignez ensuite les fichiers temporaires sur le premier champ, et la sortie de la seconde terrain.