Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 18/12/2007, à 12:54

Gari

[bash] read et les espaces en début de ligne

Bonjour à  tous,

Je suis sur un problème qui me pose bien des soucis.
Je dispose de deux fichiers dont chaque ligne correspond à  un "enregistrement".
Je souhaite savoir si les enregistrements du premier fichier sont dans le second.
Pour cela, je lis le premier fichier avec cat, j'en extrais chaque ligne avec read, puis je teste si la ligne se trouve dans le second fichier avec grep.

 cat $FicAvant | while read compte
   do
      egrep "^$compte" $FicApres > /dev/null ?>$1
      [[ $? == '0' ]] && echo "ok" || echo "ko"
   done

Le problème, c'est que mes lignes (enregistrements) peuvent commencer par des espaces (zéro, un ou plusieurs). Or, le "read" semble manger les espaces de début de ligne... donc le egrep ne fonctionne pas.
Exemple :

#cat FicAvant
 1
 2
13
   41
#cat FicApres
 1
2

Dans ce cas, l'enregistrement '1' est bien dans FicAvant et dans FicApres, mais le egrep ne le détecte pas. A noter que l'enregistrement '2' n'est pas le même dans les deux fichiers (puisque celui de FicApres ne commence pas par un espace). Il n'est pas question de considérer les deux comme étant identiques (bref : on doit laisser le '^' dans le egrep). Pourtant, il est détecté puisque l'espace de début est bouffé lors de la lecture de FicAvant.

Un exemple de ce que la commande read me donne

#cat FicAvant | read compte && echo "$compte"
1

On voit qu'elle m'a bouffé l'espace de début de ligne.

Merci à  ceux qui sauraient comment gérer ça (je suis ok pour utiliser tout autre méthode de comparaison, je ne tiens pas spécialement à  utiliser read !)

Gari.

Hors ligne

#2 Le 18/12/2007, à 13:44

Sorlingues

Re : [bash] read et les espaces en début de ligne

Salut,

Je n'avais jamais fait attention à ce détail. La lecture de
     help read
n'aide pas vraiment.

Par contre je constate que head et tail n'ont pas ce comportement d'où l'idée de ne pas utiliser read pour lire la n ème ligne mais bien une commande

head -n $FicAvant | tail -1

qui est plus ennuyeuse puisque tu devras utiliser une variable pour compter la ligne.

Une solution plus simple serait peut-être d'utiliser sed mais je ne le connais pas assez.

Hors ligne

#3 Le 18/12/2007, à 13:59

Gari

Re : [bash] read et les espaces en début de ligne

Merci Sorlingues

En cherchant dans tous les sens, et notamment en extirpant une astuce d'un forum du fin fond du net, je viens de tomber sur une solution, que j'intégre au code de mon premier post :

cat $FicAvant | while IFS= read compte
   do
      egrep "^$compte" $FicApres > /dev/null ?>$1
      [[ $? == '0' ]] && echo "ok" || echo "ko"
   done

Par contre, je n'ai pas trop suivi à  quoi pouvait bien servir le IFS... Il me semblait c'était la variable contenant le caractère de séparation de champs en entrée, mais là  je ne vois pas ce qu'il vient faire là .
En tout cas, ça marche avec.

[Edit: ma remarque sur echo était fausse, je l'ai supprimée]

Dernière modification par Gari (Le 18/12/2007, à 14:05)

Hors ligne

#4 Le 18/12/2007, à 14:23

freebird

Re : [bash] read et les espaces en début de ligne

Je l'ai appris il y a peu de temps : IFS = Internal Field Separator, le séparateur de valeur.
Par défaut c'est l'espace d'o๠le problème rencontré ici. En lui spécifiant autre chose que l'espace tu évites que le read te vires les espaces entre tes valeurs. Le plus propre serait de mettre IFS="\n" pour lui indiquer que le séparateur c'est le retour à  la ligne.

IFS="\n"
cat $FicAvant | while read compte
   do
      egrep "^$compte" $FicApres > /dev/null ?>$1
      [[ $? == '0' ]] && echo "ok" || echo "ko"
   done

Avant de connaà®tre IFS j'aurais écrit ça de la manière suivante :

exec 3< $FicAvant
while read -u3 compte
   do
      egrep "^$compte" $FicApres > /dev/null ?>$1
      [[ $? == '0' ]] && echo "ok" || echo "ko"
   done
exec 3<&-

Hors ligne

#5 Le 18/12/2007, à 14:25

Gari

Re : [bash] read et les espaces en début de ligne

Merci freebird.
Ta solution avec exec m'est totalement obscure, je vais me pencher un peu dessus pour voir un peu de quoi il s'agit.

Hors ligne

#6 Le 18/12/2007, à 14:42

yleetiny

Re : [bash] read et les espaces en début de ligne

une idée plus simple (à  tester):

cat $Fic1 $Fic2 | sort | uniq -u

personnellement si ton format de sortie importe peut tu peux utiliser la commande
"diff"

Euh, voici avec ta version "ok"/"ko", si c'est que tu souhaites plus particulièrement.

 [[ "$(cat $Fic1 $Fic2 | sort | uniq -u)" = "" ]] && echo "ok" || echo "ko"

Dernière modification par yleetiny (Le 18/12/2007, à 20:10)


Ordinateurs : SONY VAIO C2Z/B & EEEPC 701
Merci de mettre [RESOLU] dans vos postes si le problème est réglé,
et Merci de partager vos expériences

Hors ligne

#7 Le 18/12/2007, à 15:45

Gari

Re : [bash] read et les espaces en début de ligne

yleetiny, j'aime bien ton idée. elle ne permet pas de résoudre tout à  fait mon problème (que je n'ai pas exposé en entier, donc c'est normal tongue) mais ca fait déjà  beaucoup !
Je vais aussi me pencher dessus...

Merci !

Hors ligne

#8 Le 18/12/2007, à 15:48

freebird

Re : [bash] read et les espaces en début de ligne

Vu que je suis loin de maà®triser l'intégralité du fonctionnement de la commande exec je vais essayer de trouver de la doc.
Toutefois, je vais essayer d'expliquer ce que permet de faire la combinaison "exec" et "read -u" (tu peux avoir une explication en faisant man read) :

exec 3< $FicAvant # je définie que dans l'entrée standard 3 permettra de lire le contenu du fichier $FicAvant comme si il était saisi manuellement au clavier
while read -u3 compte # je lis l'entrée numéro 3 avec l'option "-u3"
   do
      egrep "^$compte" $FicApres > /dev/null ?>$1
      [[ $? == '0' ]] && echo "ok" || echo "ko"
   done
exec 3<&- # libération de l'entrée standard 3

Hors ligne

#9 Le 18/12/2007, à 20:19

yleetiny

Re : [bash] read et les espaces en début de ligne

un petit lien bien sympathique ou tu trouveras surement ton bonheur sur les scripts bash:
http://abs.traduc.org/abs-5.0-fr/ch15s04.html

Dernière modification par yleetiny (Le 18/12/2007, à 20:30)


Ordinateurs : SONY VAIO C2Z/B & EEEPC 701
Merci de mettre [RESOLU] dans vos postes si le problème est réglé,
et Merci de partager vos expériences

Hors ligne

#10 Le 18/12/2007, à 21:16

aleph

Re : [bash] read et les espaces en début de ligne

#-*- coding: iso-8859-1 -*-

# Python 2.5

### test ############################################

# test

#~ aaa.txt

#~ 111 112 113
#~    211 212 213
#~  311 312 313

#~ bbb.txt

#~ 111 112 113
#~   211 212 213   (avec des blancs en fin de ligne)

#~ ccc.txt

#~ 111 112 113
#~ 211 212 213
#~ 311 312 313

#####################################################

#~ Notes:
#~ - les fichiers ne sont lus qu'une seule et unique fois par le système
     #~ et en une seule passe.
#~ - Python: attention à  l'encodage des fichiers
     
#####################################################


def main():
    
    fn1 = 'aaa.txt'
    fn2 = 'bbb.txt'
    fn3 = 'ccc.txt'

    #lecture des fichiers dans un tableau de lignes
    f = open(fn1, 'r')
    lignes1 = f.readlines()
    f.close()

    f = open(fn2, 'r')
    lignes2 = f.readlines()
    f.close()
    
    #suppression des caractères non imprimables en début et fin de lignes
    lignes1 = [e.strip() for e in lignes1]
    lignes2 = [e.strip() for e in lignes2]
    
    #parcours lignes1, compare la ligne avec lignes2 et ajoute si absent
    for e in lignes1:
        if e not in lignes2:
            lignes2.append(e)
    
    #ajoute un \n à  chaque ligne, oté auparavant
    lignes2 = [e + '\n' for e in lignes2]

    #enregistrement du résultat
    f = open(fn3, 'w')
    f.writelines(lignes2)
    f.close()

if __name__ == '__main__':
    main()