IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Shell et commandes GNU Discussion :

[bash] Rechercher une donnée et la copier vers un autre fichier


Sujet :

Shell et commandes GNU

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 14
    Points : 8
    Points
    8
    Par défaut [bash] Rechercher une donnée et la copier vers un autre fichier
    Bonjour à tous,

    J'aimerai pour un fichier personnes contenant des noms/prénoms/adresses/sexes, réalisé un script qui copie uniquement les noms/prénoms des hommes dans un fichier homme et les noms/prénoms des femmes dans un fichier femme.
    Le fichier personnes ressemble à ça :

    Homme Homme Rue de l'Homme 16 M
    Homme Homme Rue de l'Homme 18 M
    Femme Femme Rue de la Femme 20 F

    Je ne vois pas comment accéder au champ sexe, et à partir de ça, copié la ligne avec uniquement le nom/prénom. Le délimiteur (étant la tabulation) me pose également problème, car pour le champ adresse par exemple, il y en a plusieurs, donc la commande cut -d " " -f3 ne me mènera à rien. En plus de ça, je ne peux pas connaitre le nombre exacte de colonne que peut prendre l'adresse, ce qui corse encore plus la chose.

    Quelques pistes pour résoudre le problème serait la bienvenue.

    D'avance, merci.

    P.S. : Je débute dans les scripts bash, soyez indulgent. ^^

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 986
    Points
    30 986
    Billets dans le blog
    1
    Par défaut
    Bonjour

    Le shell n'est qu'un mortier permettant d'assembler divers outils dédiés aux traitements variés dont on a besoin quotidiennement. Et comme Unix/Linux est quasiment géré/paramétré par des fichiers textes, Unix/Linux regorge d'outils dédiés à la manipulation de ces fichiers texte.
    Donc tout ce que tu as à faire est de connaitre et savoir utiliser ces outils et comme ça tu n'as plus rien à faire d'autre dans tes scripts que de les appeler quand tu en as besoin.

    Citation Envoyé par Mendozaa Voir le message
    Quelques pistes pour résoudre le problème serait la bienvenue.
    Bon, déjà le très basique grep (Global Regular Expression Print/Parser/Pattern), outil dédié à extraire certaines lignes d'un fichier en fonction d'un motif sensé s'y trouver
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    grep " M$" personnes >hommes            # Redirige vers le fichier "hommes" toutes les lignes se terminant par " M" (attention, j'ai mis une tabulation devant "M" puisque c'est le délimiteur)
    grep " F$" personnes >femmes            # Même principe
    Tu remarqueras que plus le motif demandé est large, moins il y a de risque d'obtenir de mauvais résultats. J'aurais parfaitement pu demander juste "M". Mais en demandant " M", j'élimine le risque (éventuel) de voir surgir des lignes se terminant accidentellement par "xxxM" (comme par exemple des lignes de commentaires). Bien entendu je n'élimine pas le risque de récupérer une ligne de commentaire se terminant par " M" (le risque zéro n'existe pas) mais ensuite tout est une question de rapport "complexité de l'algo/probabilité du risque à gérer"...

    Ensuite, si tu veux créer un algo plus complexe, style "que les hommes majeurs" ou autre, alors faudra passer par le très puissant mais un peu plus complexe "awk". Il s'agit d'un outil dédié au traitement de fichiers textes dans lequel tu as instantanément accès de façon individuelle à chaque mot de ta ligne (awk traitant en effet le fichier ligne par ligne) par sa position numérotée dans la ligne préfixée par un "$" ($1, $2, $3, ...) et dans lequel tu peux programmer un algo complet (avec des boucles, des alternatives, des variables) selon la valeur de ces mots.

    Exemple
    Code awk : Sélectionner tout - Visualiser dans une fenêtre à part
    awk '{if ($NF == "M" && $(NF - 1) > 18) printf("%s\n", $0)}' personnes
    NF étant le nombre de mots de la ligne en cours, $NF symbolise alors le dernier mot de la ligne et $(NF - 1) l'avant dernier. Et $0 représente la ligne entière.

    Bon ce petit exemple est minime comparé aux possibilités qu'offre awk qui méritent un livre complet. Bien entendu, plus un outil est puissant plus il est complexe à mettre en oeuvre et lourd à s'exécuter donc le choix d'utiliser tel ou tel outil aura alors une forte influence sur la rapidité de ton script...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 14
    Points : 8
    Points
    8
    Par défaut
    Malheureusement, nous n'avons pas vu la fonction awk au cours, donc je ne pourrai pas l'utiliser pour ce script. Néanmoins, les deux grep me conviennent parfaitement.

    Du coup, j'ai réussi à soutirer les noms/prénoms du fichier comme ça : grep "M$" personnes | cut -f1-2 > hommes

    J'ai d'ailleurs essayé ceci : grep "M$" personnes | tr -s " " | cut -f1-2 > hommes, ce qui me donne le même résultat, seulement les doublons d'espace ne sont pas supprimer. Est-ce que la tabulation n'est pas considéré comme une suite d'espace ?

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 986
    Points
    30 986
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Mendozaa Voir le message
    Malheureusement, nous n'avons pas vu la fonction awk au cours, donc je ne pourrai pas l'utiliser pour ce script.
    Exact. Surtout que chaque exercice donné est toujours réalisable avec les outils déjà vus. Et attention, awk n'est pas une fonction mais un outil (un programme externe indépendant). La force du shell est en effet de pouvoir utiliser ces outils comme si c'étaient des fonctions mais ce n'en sont pas...

    Citation Envoyé par Mendozaa Voir le message
    Du coup, j'ai réussi à soutirer les noms/prénoms du fichier comme ça : grep "M$" personnes | cut -f1-2 > hommes
    Oui, je n'avais pas vu que tu ne voulais qu'une partie de la ligne et donc t'as bien trouvé (ne garder avec un cut que les infos utiles de ce qui a été extrait avec grep).
    Et donc t'as bien pigé l'idée du mortier et de l'imbrication des outils => tous les outils ne font que des actions très basiques mais en les liant par des pipes, tu peux réaliser de grandes choses (une fois j'ai transformé un fichier texte en un annuaire LDAP en utilisant 7 pipes). Et si ça ne suffit pas, alors t'as encore à ta disposition des variables te permettant de mémoriser des résultats (var=$(commande)) pour les réutiliser plus tard (echo "$var" | autre_commande)...

    Citation Envoyé par Mendozaa Voir le message
    Est-ce que la tabulation n'est pas considéré comme une suite d'espace ?
    Ben non. La tabulation est un caractère bien précis (code 9 dans la table ascii) alors que l'espace en est un autre (code 32). Faut pas confondre "ce qui est" et "ce que l'écran te montre" surtout quand ce dernier transforme certains caractères pour une vision humaine plus confortable comme par exemple le "return" (symbolisé par un "\n") transformé en une nouvelle ligne...

    Exemple (à essayer toi-même)
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    a=$(seq 10)
    echo $a
    echo "$a"
    echo "$a" |od -c
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 14
    Points : 8
    Points
    8
    Par défaut
    J'ai fait ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    #! /bin/sh
     
    if [ $# -lt 1 ]; then
    	echo "Le paramètre est manquant"
    	echo "Press any character to continue"
    	read rien
    	exit 1
    fi
     
    if [ -r $1 ]; then
    	nomM=`grep "M$" $1 | cut -f1`
    	prenomM=`grep "M$" $1 | cut -f2`
    	nomF=`grep "F$" $1 | cut -f1`
    	prenomF=`grep "F$" $1 | cut -f2`
    fi
     
    chaineM="$nomM , $prenomM"
    chaineF="$nomF , $prenomF"
     
    $chaineM > hommes
    $chaineF > femmes
    Est-ce que les deux assignations pour les variables chaineM et chaineF sont correcte ? J'aimerai simplement écrire dans le fichier le nom et le prénom avec une virgule entre les deux.

    En l’exécutant, j'ai une erreur sur les deux dernières lignes. Comment faire comprendre au script que hommes et femmes sont des fichiers et pas des variables ?

  6. #6
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 986
    Points
    30 986
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Mendozaa Voir le message
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #! /bin/sh
     
    if [ $# -lt 1 ]; then
    	echo "Le paramètre est manquant"
    	echo "Press any character to continue"
    	read rien
    	exit 1
    fi
    Ok, sauf que le read est inutile. S'il n'y a pas de paramètre alors le script s'arrête et voilà.

    Citation Envoyé par Mendozaa Voir le message
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    if [ -r $1 ]; then
    	nomM=`grep "M$" $1 | cut -f1`
    	prenomM=`grep "M$" $1 | cut -f2`
    	nomF=`grep "F$" $1 | cut -f1`
    	prenomF=`grep "F$" $1 | cut -f2`
    fi
    Dommage tous ces grep répétés. N'oublie pas qu'un grep entrainera une lecture et une analyse du fichier. Aussi rapide que ce soit, le temps nécessaire au grep sera ici inutilement doublé...
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    if [ -r $1 ]; then
    	homme=`grep "M$" $1`
    	femme=`grep "F$" $1`
    	nomM=`echo "$homme" | cut -f1`
    	prenomM=`echo "$homme" | cut -f2`
    	nomF=`echo "$femme" | cut -f1`
    	prenomF=`echo "$femme" | cut -f2`
    fi

    Citation Envoyé par Mendozaa Voir le message
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    chaineM="$nomM , $prenomM"
    chaineF="$nomF , $prenomF"
     
    $chaineM > hommes
    $chaineF > femmes

    Est-ce que les deux assignations pour les variables chaineM et chaineF sont correcte ?
    Oui, tout à fait. Sauf que cette assignation est inutile dans le cas où le script n'est pas rentré dans le "if [-r $1]"...

    Citation Envoyé par Mendozaa Voir le message
    En l’exécutant, j'ai une erreur sur les deux dernières lignes. Comment faire comprendre au script que hommes et femmes sont des fichiers et pas des variables ?
    T'as une erreur parce que le premier mot d'une ligne shell doit impérativement être une instruction shell ou une commande. Or, "$chaineM" (étant alors remplacé par son contenu) ne contient pas d'instruction ou de commande !!!

    T'as la solution dans mon exemple d'au dessus...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  7. #7
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 14
    Points : 8
    Points
    8
    Par défaut
    Avec les modif apporté, ça me donne ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    #! /bin/sh
     
    if [ $# -lt 1 ]; then
    	echo "Le paramètre est manquant"
    	echo "Press any character to continue"
    	read rien
    	exit 1
    fi
     
    if [ -r $1 ]; then
    	homme=`grep "M$" $1`
    	femme=`grep "F$" $1`
    	nomM=`echo "$homme" | cut -f1`
    	prenomM=`echo "$homme" | cut -f2`
    	nomF=`echo "$femme" | cut -f1`
    	prenomF=`echo "$femme" | cut -f2`
    	chaineM="$nomM , $prenomM"
    	chaineF="$nomF , $prenomF"
    fi
     
    echo $chaineM >> $2
    echo $chaineF >> $3
    Seulement, j'ai ceci comme résultat :

    NomDeF NomDeF , Prénom Prénom

    Alors que le résultat attendu était plutôt :

    NomDeF , Prénom
    NomDeF , Prénom

    (pour le fichier hommes, étant donné qu'ils sont deux)

    Du coup, j'ai un peu remanié le code et j'y ai ajouté deux boucles for (pensant que c'était la chose à faire), une pour les hommes, une pour les femmes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    #! /bin/sh
     
    if [ $# -lt 1 ]; then
    	echo "Le paramètre est manquant"
    	echo "Press any character to continue"
    	read rien
    	exit 1
    fi
     
    if [ -r $1 ]; then
    	for i in `grep "M$" $1`; do
    		nomM=`echo $i | cut -f1`
    		prenomM=`echo $i | cut -f2`
    		chaineM="$nomM , $prenomM"
    		echo $chaineM >> $2
    	done
     
    	for i in `grep "F$" $1`; do
    		nomF=`echo $i | cut -f1`
    		prenomF=`echo $i | cut -f2`
    		chaineF="$nomF , $prenomF"
    		echo $chaineF >> $3
    	done		
    fi
    Le soucis avec cette version, c'est qu'il m'écrit tout les champs dans le fichier, du style :

    M , M
    NomDeF , NomDeF
    Prénom , Prénom
    Rue , Rue

    Et ainsi de suite.

  8. #8
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 986
    Points
    30 986
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Mendozaa Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    echo $chaineM >> $2
    echo $chaineF >> $3
    C'est bien d'avoir pensé au echo. C'était en effet ce qui manquait !!!

    Citation Envoyé par Mendozaa Voir le message
    Seulement, j'ai ceci comme résultat :

    NomDeF NomDeF , Prénom Prénom

    Alors que le résultat attendu était plutôt :

    NomDeF , Prénom
    NomDeF , Prénom

    (pour le fichier hommes, étant donné qu'ils sont deux)
    Oui c'est vrai. J'avais pas repensé au contenu du fichier d'origine. Mais au départ ton besoin était juste "envoyer les hommes à part". Or maintenant il faut les traiter...

    Citation Envoyé par Mendozaa Voir le message
    Du coup, j'ai un peu remanié le code et j'y ai ajouté deux boucles for (pensant que c'était la chose à faire)
    Exact, c'est en effet le truc à faire...

    Citation Envoyé par Mendozaa Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    for i in `grep "M$" $1`; do
    		nomM=`echo $i | cut -f1`
    		prenomM=`echo $i | cut -f2`
    		chaineM="$nomM , $prenomM"
    		echo $chaineM >> $2
    	done
    ... mais faut le faire bien. Tu sais très bien que le for utilise l'espace pour séparer ses éléments. Or, toi, tu veux traiter non pas un mot après l'autre mais une ligne après l'autre.
    Pour ça, faut utiliser une commande qui prend une fin de ligne comme élément marquant. Or une fin de ligne étant un <return>, la commande qui sait traiter un <return> est le read !!!
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    grep "M$" "$1" | while read ligne
    do
    	nomM=`echo "$ligne" | cut -f1`
    	prenomM=`echo "$ligne" | cut -f2`
    	echo "$nomM , $prenomM" >> "$2"
    done

    Citation Envoyé par Mendozaa Voir le message
    , une pour les hommes, une pour les femmes :
    A ce niveau là, le grep perd de son intérêt. Au départ il était pratique de l'utiliser pour extraire juste les hommes d'un coté puis les femmes d'un autre. Il faisait ça en une fois de façon hyper rapide.
    Maintenant tu rajoutes derrière un traitement un petit peu complexe appliqué à chque ligne du grep (on perd l'avantage de sa rapidité); traitement que tu dois en plus dupliquer pour les hommes et les femmes (tu multiplies par deux la complexité de ton code).

    Autant supprimer le grep et faire la distinction hommes/femmes directement dans le traitement. Ca ne l'alourdira pas beaucoup plus et tu auras l'avantage de n'avoir à l'écrire qu'une fois...

    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    cat "$1" | while read ligne
    do
    	nom=`echo "$ligne" | cut -f1`
    	prenom=`echo "$ligne" | cut -f2`
    	test "`echo $ligne | cut -f5`" = "M" && dest="$2" || dest="$3"
    	echo "$nom , $prenom" >> "$dest"
    done
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  9. #9
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 14
    Points : 8
    Points
    8
    Par défaut
    La version finale :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    #! /bin/sh
     
    if [ $# -lt 1 ]; then
    	echo "Le paramètre est manquant"
    	echo "Press any character to continue"
    	read rien
    	exit 1
    fi
     
    if [ -r $1 ]; then
    	cat "$1" | while read ligne
    	do
    		nom=`echo "$ligne" | cut -f1`
    		prenom=`echo "$ligne" | cut -f2`
    		sexe=`echo "$ligne" | cut -f4`
    		if [ $sexe == "M" ]; then
    			echo "$nom , $prenom" >> $2
    		else
    			echo "$nom , $prenom" >> $3
    		fi
    	done
    fi
    Et ça fonctionne parfaitement, super ! Au premier lancement, il y avait des manquements dans les deux fichiers hommes et femmes, le soucis venait en faite des tabulations, car pour certains noms courts, il fallait deux tabulations pour que le prénom soit au même niveau que le prénom du dessus, ce qui fait que ce prénom là ne se situait pas dans la même colonne que le précédent, comme tu l'as très bien dis :

    Faut pas confondre "ce qui est" et "ce que l'écran te montre"
    Quoiqu'il en soit, un très GRAND merci pour ta précieuse aide.

  10. #10
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 986
    Points
    30 986
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Mendozaa Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #! /bin/sh
    sexe=`echo "$ligne" | cut -f4`
    if [ $sexe == "M" ]; then
    	echo "$nom , $prenom" >> $2
    else
    	echo "$nom , $prenom" >> $3
    fi
    Dommage, tu n'as pas gardé mon dest="$2" || dest="$3". Pourtant là encore tu fais une duplication. Minime mais une duplication quand-même...
    Pense à toujours encadrer tes variables sensées contenir des chaines par des guillemets (surtout dans un test). Dans cet exemple précis ce n'est pas grave mais il y a des cas où ça te sauvera ton test (surtout dans le cas d'une variable vide) => if [ "$sexe" == "M" ]; then.
    Et si la variable n'est utilisée qu'une fois, tu peux alors t'en passer => if [ "`echo $ligne | cut -f4`" == "M" ]; then. Un peu difficile à relire au début mais tu verras que ça vient vite...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #! /bin/sh
    if [ "`echo $ligne | cut -f4`" == "M" ]; then
    	dest="$2"
    else
    	dest="$3"
    fi
    echo "$nom , $prenom" >> "$dest"
    Et si le then/else ne possède qu'une instruction, tu peux alors simplifier avec l'autre outil programme && instruction_si_vrai || instruction_si_faux
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #! /bin/sh
    [ "`echo $ligne | cut -f4`" == "M" ] && dest="$2" || dest="$3"
    echo "$nom , $prenom" >> "$dest"
    Citation Envoyé par Mendozaa Voir le message
    Au premier lancement, il y avait des manquements dans les deux fichiers hommes et femmes, le soucis venait en faite des tabulations, car pour certains noms courts, il fallait deux tabulations pour que le prénom soit au même niveau que le prénom du dessus, ce qui fait que ce prénom là ne se situait pas dans la même colonne que le précédent
    Ah oui, c'est en effet super grave. Il vaut mieux avoir un fichier bien carré. Tant pis si à l'affichage ça rend pas bien, l'important c'est que ton script, lui, puisse le traiter correctement !!!

    Citation Envoyé par Mendozaa Voir le message
    Quoiqu'il en soit, un très GRAND merci pour ta précieuse aide.
    On est là pour ça (et on est nombreux en plus). Ceci dit, je n'ai pas fait grand chose car tu t'es surtout aidé tout seul (t'es vif, tu comprends vite les choses). C'est plus à toi-même que tu dois ton résultat qu'à moi qui n'ai fait que te montrer où regarder.
    Bienvenue sur ce forum
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  11. #11
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 14
    Points : 8
    Points
    8
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Dommage, tu n'as pas gardé mon dest="$2" || dest="$3". Pourtant là encore tu fais une duplication. Minime mais une duplication quand-même...
    Je n'avais pas très bien compris son utilité dans le post précédent, mais là avec le code c'est plus clair.
    Seulement, avec cette modif, tout les noms/prénoms sont écrit seulement dans le fichier femmes (le scripte passe directement au else), et le fichier hommes ne se crée pas.

    Le code si jamais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    #! /bin/sh
     
    if [ $# -lt 1 ]; then
    	echo "Le paramètre est manquant"
    	echo "Press any character to continue"
    	read rien
    	exit 1
    fi
     
    if [ -r $1 ]; then
    	cat "$1" | while read ligne
    	do
    		nom=`echo "$ligne" | cut -f1`
    		prenom=`echo "$ligne" | cut -f2`
    		if [ "`echo $ligne | cut -f4`" == "M" ]; then
    			dest="$2"
    		else
    			dest="$3"
    		fi
    		echo "$nom , $prenom" >> "$dest"
    	done
    fi
    Citation Envoyé par Sve@r Voir le message
    On est là pour ça (et on est nombreux en plus). Ceci dit, je n'ai pas fait grand chose car tu t'es surtout aidé tout seul (t'es vif, tu comprends vite les choses). C'est plus à toi-même que tu dois ton résultat qu'à moi qui n'ai fait que te montrer où regarder.
    Bienvenue sur ce forum
    Merci.

  12. #12
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 986
    Points
    30 986
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Mendozaa Voir le message
    Seulement, avec cette modif, tout les noms/prénoms sont écrit seulement dans le fichier femmes (le scripte passe directement au else), et le fichier hommes ne se crée pas.
    Petite erreur de ma part et aussi de la tienne
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    if [ `echo "$ligne" | cut -f4` = "M" ]; then
    Ton erreur: il ne faut qu'un seul "=" dans le test et non "=="
    Mon erreur: les guillemets se mettent autour de "$ligne". Sans ça, le shell interprète les tabulations qui y sont contenues comme un espace et le cut ne peut pas isoler le 4° champ (M ou F)

    Pour être vraiment propre, il faudrait toutefois encadrer le tout par des guillemets. Ca protège alors le cas où l'expression ne renvoie rien. Mais ça oblige alors à protéger les guillemets intérieurs par des backslashes...
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    if [ "`echo \"$ligne\" | cut -f4`" = "M" ]; then
    ... et ça devient plus lourd et plus complexe (le prix de la sécurité)...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  13. #13
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 14
    Points : 8
    Points
    8
    Par défaut
    J'ai essayé, et les deux fonctionnent (=/==). D'ailleurs, le simple "=" n'est pas fait pour assigner une valeur à variable ? Du style : var=5.

    Et le -eq dans tout ça ?

  14. #14
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 986
    Points
    30 986
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Mendozaa Voir le message
    J'ai essayé, et les deux fonctionnent (=/==).
    Mouais. Moi j'ai eu une erreur que je n'avais plus quand je mettais "=". J'ai pas cherché plus loin (surtout que historiquement, la bonne syntaxe est "=").

    Citation Envoyé par Mendozaa Voir le message
    D'ailleurs, le simple "=" n'est pas fait pour assigner une valeur à variable ? Du style : var=5.
    Ouh là, faut pas tout confondre Johnny !!!
    • var=5 se trouve être une instruction interne shell (un "shell built-in"). Cette instruction demande effectivement une affectation de 5 dans var. Accessoirement tu noteras qu'il ne faut pas d'espace avant le "=" car sinon (exemple var =5), le shell interprètera cette instruction comme "appel de la commande var avec le paramètre =5".
    • test "$var" = "5" (ou, alias, [ "$var" = "5" ]) se trouve être l'appel de la commande "test" (/usr/bin/test) avec 3 paramètres: "$var", "=" et "5". Et c'est avec ces 3 paramètres que le programme "/usr/bin/test" saura quoi comparer avec quoi et de quelle façon. Et là, inversement avec l'exemple du dessus (même s'il n'y a aucun rapport entre les deux instructions qui font appel à deux choses totalement différentes), il faut impérativement espacer les éléments afin que /usr/bin/test sache bien les distinguer. Et c'est aussi pour ça qu'il faut encadrer une variable avec des guillemets => afin que même si elle est vide, le programme "test" ait quelque chose en position n° 1 à comparer avec quelque chose en position n° 3.


    Citation Envoyé par Mendozaa Voir le message
    Et le -eq dans tout ça ?
    Même raison: pour que le programme test sache que tu veux faire une comparaison numérique (par opposition au "=" qui est fait pour comparer des chaines)
    • test 00005 = 5 => te renverra "faux" alors que mathématiquement c'est vrai
    • test 00005 -eq 5 => te renverra "vrai"
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  15. #15
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 14
    Points : 8
    Points
    8
    Par défaut
    Donc :

    "=" --> comparaison alphabétique
    "-eq" --> comparaison numérique

    Et le == ?

  16. #16
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 290
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 290
    Points : 12 756
    Points
    12 756
    Par défaut
    Bonjour,
    Citation Envoyé par Sve@r Voir le message
    Pour être vraiment propre, il faudrait toutefois encadrer le tout par des guillemets. Ca protège alors le cas où l'expression ne renvoie rien. Mais ça oblige alors à protéger les guillemets intérieurs par des backslashes...
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    if [ "`echo \"$ligne\" | cut -f4`" = "M" ]; then
    ... et ça devient plus lourd et plus complexe (le prix de la sécurité)...
    Ici, je ne suis pas sur que les backslash soient obligatoires:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $ echo "$bob" | od -c
    0000000   t   o   t   o  \t   t   i   t   i  \t   p   a   p   a  \n
    0000017
    $ echo "`echo $bob | cut -f3`"
    toto titi papa
    $ echo "`echo "$bob" | cut -f3`"
    papa
    Cordialement.

  17. #17
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 290
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 290
    Points : 12 756
    Points
    12 756
    Par défaut
    Citation Envoyé par Mendozaa Voir le message
    Donc :

    "=" --> comparaison alphabétique
    "-eq" --> comparaison numérique

    Et le == ?
    En bash, identique au "=" sinon de manière générale, la plupart des shell supporte "=" , ce qui n'est pas le cas de "==" .
    Cordialement.

  18. #18
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 986
    Points
    30 986
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par disedorgue Voir le message
    Ici, je ne suis pas sur que les backslash soient obligatoires:
    Ben chez moi...
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    bob="toto  titi tata"                # Une tabulation entre "toto" et "titi" et un espace entre "titi" et "tata"
    $ echo "$bob" |cut -f2
    titi tata
    $ echo $bob |cut -f2
    toto titi tata
    $ bash --version
    GNU bash, version 4.1.5(1)-release (i486-pc-linux-gnu)
    Donc si les guillemets sont obligatoires autour de la variable, et si on veut en plus encadrer toute l'expression par des guillemets, les guillemets autour de la variable devront être protégés non ?

    Quand au "==", après 15 mn de recherche et de tests en tous sens, j'ai compris !!! Regarde les différents codes de Mendozaa au fil de ce post (que je recopiais alors chez-moi pour ensuite les corriger), il a son shebang en /bin/sh !!!
    Or chez-moi, (Debian Sqeeze), mon /bin/sh pointe vers /bin/dash. Et dash semble ne pas accepter le "=="
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ dash
    $ test "x" == "x"
    test: 2: x: unexpected operator
    $

    Le plus drole, c'est que quand je testais en script ça ne fonctionnait pas mais quand je testais en ligne de commande (bash par défaut) ça fonctionnait. J'ai cru devenir dingue
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  19. #19
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 290
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 290
    Points : 12 756
    Points
    12 756
    Par défaut
    A aucun moment, je parle de viré les guillemets, je dis juste que les "\" sont inutiles dans l'encadrement, ce que je montre dans mon exemple.
    En fait, il semble protégés par les syntaxes ` ... ` ou $( ... ), mais je suis aussi dubitatif...

    Pour le shebang, je n'avais pas trop fait attention, mais je répondais globalement, et de toute façon en mon sens il faut proscrire le "==" autant que possible.
    Cordialement.

  20. #20
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 14
    Points : 8
    Points
    8
    Par défaut
    Merci à vous deux pour les précisions.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. copier une base de données d'un ordinateur vers un autre
    Par ck23 dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 13/01/2011, 00h36
  2. Réponses: 20
    Dernier message: 01/02/2008, 14h21
  3. Copier une liste d'un site vers un autre
    Par LefortLudovic dans le forum SharePoint
    Réponses: 4
    Dernier message: 06/09/2007, 14h52
  4. [SQL] Comment rechercher une donnée selon un critère !
    Par Il_TiRaNNo dans le forum PHP & Base de données
    Réponses: 12
    Dernier message: 09/05/2007, 14h59
  5. copier une base d'un serveur vers un autre
    Par julien.63 dans le forum PostgreSQL
    Réponses: 2
    Dernier message: 28/03/2007, 14h18

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo