Traitement d'un fichier avec unix

hin175

Membre confirmé
7 Décembre 2006
11
0
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
>Gene29912
>Gene29912
>Gene29912
>Gene3
>Gene29925
>Gene29925
>Gene29928
>Gene29928
>Gene29942
>Gene4
>Gene29986
>Gene29986
>Gene30035
>Gene30035
>Gene30049
...

Et un qui contient les caractéristiques de ces noms :
>Gene1
MSVEITGI
>Gene2
MSVESSSGSGDRITVNPDPIH
>Gene3
MMNQ
>Gene4
MVKFTADELRRIMDYKHNIRNMSVIAQ
...

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 !
 
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 .
 
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
>Gene1
MSVEITGI
>Gene1
MSVEITGI
> Gene29912
MSVESSSGSGDRITVNPDPIH
> Gene29912
MSVESSSGSGDRITVNPDPIH
> Gene29912
MSVESSSGSGDRITVGSGHHJJJNPDPIH
>Gene3
MMNQ
> Gene29925
MVKFTADELRRIMDYHSAQQDTFKHNIRNMSVIAQ
...

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... ;-)
 
Si j'ai bien compris, le but est simplement d'extraire du fichier 2 les éléments indiqués par le fichier 1 ?
 
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 çà.
 
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.)
 
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.
 
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...

(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];

open IN,$fastafile;
while (<IN>)
{
chomp;
if (/^>/)
{
$nom=$_;
$hash{$nom}='';
}
else
{
$hash{$nom}.=$_;
}
}
close IN;


open F,$reffile;

while ($x = <F>) {
if ($x =~ /\|/) {
chomp $x;
($a,$b) = split (" ", $x);
$a =~ s/\|/\\\|/g;
foreach $cle (keys %hash)
{
if ($cle =~ /$a/)
{
print "$cle\n";
}
}
}
}
 
Bon on ne va pas s'emmerder avec du PERL (et sa syntaxe dégueulasse ;p).

A l'arrache:

Bloc de code:
#!/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
 
Dernière édition:
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 !
 
Ah bon ? Je ne connaissais pas.
 
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)