# Traitement d'un fichier avec unix



## hin175 (10 Août 2014)

Bonjour à tous,
cela fait un moment que je cherche sans trouver de solutions....
J'ai 2 fichiers, un qui contient une liste de noms :


> >Gene29857
> >Gene1
> >Gene1
> >Gene1
> ...



Et un qui contient les caractéristiques de ces noms :


> >Gene1
> MSVEITGI
> >Gene2
> MSVESSSGSGDRITVNPDPIH
> ...



Je voudrais récupérer les ensembles noms+caractéristiques dans le 2ème fichier des noms présents dans le premier fichier...
Je voudrais faire çà sur un serveur distant, donc en shell ce serait super :-D

Si quelqu'un avait une piste, ou même une solution, je suis preneur...
Merci beaucoup par avance !


----------



## bompi (10 Août 2014)

Ce n'est pas clair : on voit bien quelles sont les entrées (pas leur taille respective). Mais pas bien quel sera le résultat.

Si tu as Perl (ou Python ou Ruby) sous la main, c'est plus simple qu'avec Bash (ou ksh). Si en plus tu as SQLite, ce le sera encore davantage .


----------



## hin175 (10 Août 2014)

Merci pour ta réponse.
Les tailles des fichiers sont variables en fonction de la paire de fichiers considérés, certaines paires ayant plus de noms à vérifier (mais le fichier noms+caractéristiques est le même pour toutes les paires)...

Le résultat serait idéalement du genre (basé sur l'exemple donné dans ma question): 


> > Gene29857
> MSVEITGIFHEYDJEZW
> >Gene1
> MSVEITGI
> ...



Donc avec la paire noms+caractéristiques pour chaque noms qui apparait, même s'il apparait plusieurs fois.
Sinon, au moins la paire noms+caractéristiques une fois, même s'il y a plusieurs apparitions.

Je dois pouvoir trouver perl sur le serveur distant... ;-)


----------



## bompi (11 Août 2014)

Si j'ai bien compris, le but est simplement d'extraire du fichier 2 les éléments indiqués par le fichier 1 ?


----------



## hin175 (11 Août 2014)

c'est çà ! ;-)
Extraire du fichier 2 les 2 lignes correspondant à chaque ligne du fichier 1...
C'est vrai que c'est plus simple dit comme çà.


----------



## edd72 (11 Août 2014)

Ca semble plutôt simple.

La version non optimisée consiste simplement à parcourir le fichier 1 et pour chaque ligne parcourir le fichier 2 jusqu'à trouver la ligne correspondante et reporter cette ligne du fichier 2 et la suivante dans le fichier 3 (ensuite on passe à la suivante du fichier 1).

(la version optimisée serait de trier les deux fichier afin de n'effectuer ensuite qu'un seul parcours -ruptures-)

Quelles difficultés rencontres-tu pour le faire en Shell?

(Rassures-moi, tu ne veux pas là pour que te ponde ton code "clé en main"? Ou alors il va falloir qu'on te facture.)


----------



## bompi (11 Août 2014)

On peut imaginer :
a) lire le fichier 1 et le charger dans une table de hashage (_hashed array_)
b) lire le fichier 2 (par groupe de deux lignes) et quand l'identifiant existe dans la table, le sortir dans le fichier de résultat.

Mais, quand on aime faire un peu plus net et un peu plus travaillé, on peut aussi :
a) charger chaque fichier dans une table SQL, à l'aide de SQLite
b) faire une sélection dont on écrira le résultat dans le fichier de sortie.


----------



## hin175 (11 Août 2014)

edd72 a dit:


> Quelles difficultés rencontres-tu pour le faire en Shell?



La première difficulté est que je ne sais pas quelle commande en shel permet de faire çà...
Du coup, je pensais utiliser grep, mais là la difficulté est que j'ignore (pas trouver l'info) si on peut utiliser un fichier (ou une liste) comme variable pour la recherche, et que dans ce cas, il faut que noms+caractéristiques soient sur une seule ligne... C'est ce sur quoi j'ai commencer à bosser, mais je n'arrive pas à supprimer les retour chariots sauf ceux devant le caractère ">" (c'est vraiment çà qui bloque, quoi que je fasse, ce caractère n'est pas reconnu). J'ai passé 2 jours à chercher sur les forums et le reste du net une réponse (même partielle) à mon problème pour les différentes étapes...



edd72 a dit:


> (Rassures-moi, tu ne veux pas là pour que te ponde ton code "clé en main"? Ou alors il va falloir qu'on te facture.)



Ben... j'avoue que çà m'arrangerait ;-) Mais la fonction qui permettrait de récupérer 2 lignes (ou de mettre noms+caractères sur une ligne) m'aiderait déjà, je pourrais sans doute me débrouiller avec les manuels et d'autres exemples...

---------- Nouveau message ajouté à 17h33 ---------- Le message précédent a été envoyé à 17h26 ----------

J'ai aussi un script en perl qui est sensé faire çà, mais il ne fonctionne pas, je pense à cause d'une différence dans le formatage de mes fichiers. Et j'y comprend pas grand chose... enfin du moins je ne comprend pas pourquoi çà ne marche pas :rose:



> #!/usr/bin/perl
> 
> $fastafile=$ARGV[0];
> $reffile=$ARGV[1];
> ...


----------



## edd72 (11 Août 2014)

Bon on ne va pas s'emmerder avec du PERL (et sa syntaxe dégueulasse ;p).

A l'arrache:


```
#!/bin/bash

fichier1=$1
fichier2=$2
fichiersortie=$3

# on efface le fichier de sortie s'il existe !!!
rm $fichiersortie

# on parcourt le fichier liste
while read lignefic1  
do  
# on teste que la ligne débute bien par >
   if [ "`echo $lignefic1 | cut -c1-1`" = '>' ]
   then
       flagTrouv=0
       flagOK=0
# on cherche la correspondance dans le fichier de corresp
                while read lignefic2  
                do 
                    if [ $flagOK -eq 1 ]
                    then
                        # correspondance trouvée au passage précédent, on écrit
                        echo "$lignefic1" >> $fichiersortie
                        echo "$lignefic2" >> $fichiersortie
                    fi
                        
                   if [ "$lignefic1" = "$lignefic2" ]
                   then       
# on a trouvé la corresp, on flag pour la tracer au passage suivant (ligne suivante)
                    flagOK=1
                    flagTrouv=1
                   else
                       flagOK=0
                   fi
                done < $fichier2
                if [ $flagTrouv -eq 0 ]
                then
# on a parcouru tout le fichier sans trouver la corresp
                    echo "!!!  $lignefic1 non trouvée !!!"
                fi
   else
# La ligne du fichier en entrée est incorrecte (ne contient pas >)
    echo "!!! ligne $ligne incorrecte !!!"
   fi
done < $fichier1
```
Le programme prend 3 paramètres:
- fichier liste
- fichier de correspondance
- fichier de sortie (!! qui est effacé s'il existe)

Il indique à l'écran quand une correspondance est non trouvée.

[EDIT] ajout de quelques commentaires


----------



## hin175 (12 Août 2014)

Merci beaucoup Edd72 !
çà marche !
Désolé d'avoir pris un peu de temps pour répondre, mais j'avais oublié de préciser qu'il pouvait y avoir plusieurs lignes de lettres pour chaque gène (j'avais raccourci les séquences de gènes dans l'exemple, en oubliant que çà pouvait avoir son importance)... du coup, j'ai cherché comment mettre toute la séquence sur une seule ligne.
n'ayant qu'un seul fichier de correspondance, j'ai essayé de le faire avec excel... malheur.
Outre que c'est long (pb de mémoire) et fastidieux, ton script bash ne marchait plus...

Puis j'ai fini par trouver et adapter cette commande, qui suppriment les retour de lignes dans les séquences...


> awk '/^>/{print s? s"\n"$0:$0;s="";next}{s=s sprintf("%s",$0)}END{if(s)print s}' input.fa > output.fa



Merci à tous !


----------



## edd72 (12 Août 2014)

Ah oui, si la ligne ">" est en plusieurs lignes c'est plus embétant, surtout s'il est impossible de dissocier "la suite de la ligne >" de "la ligne d'information à récupérer ensuite".


----------



## Félix bla (4 Octobre 2014)

man diff


----------



## bompi (4 Octobre 2014)

Certes. Mais encore ?


----------



## Félix bla (4 Octobre 2014)

Rhooo je suis sur mon iPhone, sur un linux tape 'man diff' et tu liras les options !


----------



## bompi (4 Octobre 2014)

Ah bon ? Je ne connaissais pas.


----------



## edd72 (6 Octobre 2014)

Félix bla a dit:


> Rhooo je suis sur mon iPhone



Ah ouais, ce doit être pour cela que ta réponse semble sans rapport avec le besoin.
(diff servant à comparer deux fichiers pas à les apparier d'autant plus qu'ici il y a n instances d'une même ligne)


----------

