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] Extraire des lignes d'une catégorie souhaitée (sans awk)


Sujet :

Shell et commandes GNU

  1. #1
    Invité
    Invité(e)
    Par défaut [bash] Extraire des lignes d'une catégorie souhaitée (sans awk)
    Bonjour,
    Je ne parviens pas à extraire, à partir d’un champ d’un fichier ‘livres’ les différents enregistrements selon la catégorie de livres souhaitée par la personne (j’ai déjà écrit la partie du script où il faut read la catégorie du livre souhaitée par une personne et j’ai déjà récupéré les données de chaque champ).
    !!!Je ne dois pas utiliser de awk pour cet exercice qui se fait en bash… Merci à eux qui m’aideront

    Par exemple j’ai ceci,
    Nom1: Prénom1:TITRE1:2000:BD
    Nom2: Prénom2:TITRE2:2001:ROMAN
    Nom3: Prénom3:TITRE3:2002:SCIENCES
    Nom4: Prénom4:TITRE4:2003:BD
    Nom5: Prénom5:TITRE5:2004:ROMAN
    Nom6: Prénom6:TITRE6:2004:SCIENCES
    Et à la fin de mon script, je dois créer un fichier dans lequel :
    - la première ligne va m’indiquer la liste des auteurs (1re et 2e colonne) et titres de livres(3e colonne) de la catégorie (4e colonne)
    - les lignes suivantes m’indiquent le nom de l'auteur(1re colonne) ainsi que le titre des livres de la catégorie sélectionnée(3e colonne) , séparés par un -
    - la dernière ligne indique le nombre de livres trouvés

    Voici ce que j’ai déjà essayé de faire (en m’imaginant pour ‘ROMAN’) :
    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
    	#créer le fichier reprenant titre liste de livres et nombres de livres extraits
     
    	ISFold=$IFS
    	IFS=':'
    	while read nom prenom titre annee categorie
    	do
    	  function creer_fichier {
    		touch -p "/home/livres/$1"
     
    		if grep -q "^$1:" /etc/group
    		then
    			ls -l | head -1 /home/user/livres | cut -d: -f1,4 /home/user/livres
     
    		elif 
    			ls -l | tail -n+2 /home/user/livres | cut -d: -f1 "-" -f3 /home/user/livres
    		else
    			ls | wc -l | tail -1 /home/user/livres
    		fi
    		resultat=$(grep -l student/home/user/livres/*)
    	}
    	done < /home/user/livres
     
    done
    Dernière modification par Invité ; 16/07/2022 à 16h55. Motif: Ajout des balises CODE (bouton #) et QUOTE

  2. #2
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 559
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 559
    Points : 19 399
    Points
    19 399
    Par défaut
    Bonjour,

    d'abord, les fonctions sont définies au début du script, une fois pour toutes.

    il faudrait commenter ton script pour qu'on voit ce que tu veux faire, parce que là ça ne semble pas très cohérent.

    en admettant que la catégorie soit passée au script en argument :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #!/bin/bash
     
    chemin= #à définir
    fichier= #à définir
     
    while IFS=':' read nom prenom titre annee categorie
    do
        test "$categorie" = "$1" && echo "correspondance \"$categorie\" : $nom $prenom $titre $annee"
    done <"$chemin/$fichier"
    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  3. #3
    Invité
    Invité(e)
    Par défaut
    Merci infiniment pour ton commentaire car je me suis rendu compte que j'ai mal expliqué mon objectif que je vais éclaircir...

    D'abord, le but est : établir une liste qui reprend les auteurs et les titres des livres correspondant à une catégorie donnée (à partir d'un fichier livres.txt qui est déjà dans mon répertoire)
    Ensuite, j'avais essayé d'écrire une fonction creer_fichier car je ne sais pas comment faire autrement pour que le même script puisse créer un fichier (qui portera un nom au choix) et dans lequel je devrai renvoyer les données correspondant au champ de la catégorie (à ce que la personne inscrit pour le read "..." cat)
    Enfin, je ne dois pas utiliser (pour le moment) de awk, test, correspondance ... car je ne les ai pas encore vu puisque je débute à peine ma formation...


    Je laisse mon script au complet pour mieux visualiser ma démarche, mes commentaires et mes erreurs:

    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    #! /bin/bash
     
    echo
    echo "établir une liste qui reprend les auteurs et les titres des livres correspondant à une catégorie donnée"
    fich="home/user/livres.txt"
     
    #vérifie que le fichier contenant la liste des livres existe bien
    #vérifie si le chemin est fourni comme 1er arg à la cmd
    if [ -z "$1" ]
    then
    	echo "Utilisation $0 <livres.txt>"
    	echo "Aucun fichier input n'a été donné"
    	exit 1
    fi
     
    #verifie si ce meme fichier existe
    if [ ! -f "$1" ]
    then
    	echo "Le fichier $1 n existe pas"
    	exit 2
    fi
     
     
     
    #demander à l'utilisateur quelle catégorie de livres ils souhaitait extraire
     
    read -p "Quelle catégorie souhaiteriez-vous extraire ?" cat
     
    #extraire ces livres du fichier et créer un fichier avec : le titre, la liste des livres et ensuite le nombre de livres extraits
     
    while read cat
     
    do
     
           if [[ -z $cat ]]
     
                       then
     
                                   echo
     
                                   echo "ligne contenant un tiret non traitée"
     
                                   continue
     
           fi
     
        # Récupérer les données des différents champs
    	nom="$(echo "$cat" | cut -d";" -f1)"
    	prenom="$(echo "$cat" | cut -d";" -f2)"
    	titre="$(echo "$cat" | cut -d";" -f3)"
    	annee="$(echo "$cat" | cut -d";" -f4)"
    	categorie="$(echo "$cat" | cut -d";" -f5)"
     
    	# Compter le nombre de livres
     
     
    	#créer le fichier reprenant titre liste de livres et nombres de livres extraits
     
     
    	IFSold="$IFS"
    	IFS=':'
    	while read nom prenom titre annee categorie
    	do
    	  function creer_fichier {
    		touch -p "/home/livres/$1"
     
    		if grep -q "^$1:" /home/user/livres
    		then
    			ls -l | head -1 /home/user/livres | cut -d: -f1,4 /home/user/livres
     
    		elif 
    			ls -l | tail -n+2 /home/user/livres | cut -d: -f1 "-" -f3 /home/user/livres
    		else
    			ls | wc -l | tail -1 /home/user/livres
    		fi
    		resultat=$(grep -l student/home/user/livres/*)
    	}
    	done < /home/user/livres
     
    done
    Dernière modification par Invité ; 16/07/2022 à 18h13.

  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 699
    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 699
    Points : 30 999
    Points
    30 999
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Etant donné qu'une infoX est traitée plusieurs fois, et pas forcément au moment où elle est lue (typiquement si tu dois afficher la liste des auteurs sur une ligne, cela signifie que tu dois mémoriser l'auteur 1 avant de lire la ligne contenant les auteurs 2, 3, 4 et 5), tu dois donc mémoriser ce que tu lis avant de le traiter.
    Et la meilleure façon de mémoriser n infos reste encore le tableau.

    Citation Envoyé par environnementBash Voir le message
    ISFold=$IFS
    Toujours toujours toujours quoter les variables contenant du texte. Surtout si cette variable peut contenir des espaces et autres éléments que le shell assimile à un séparateur => ISFold="$IFS". Ca ne coûte rien et ça évite les bugs idiots.
    Faudra que tu m'expliques aussi ce que vient faire /etc/group dans ce programme...
    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
    Invité
    Invité(e)
    Par défaut
    Je viens d'enregistrer les modifications.
    etc/group était une bête erreur.

    Merci beaucoup d'ailleurs pour la remarque concernant le fait de quoter les variables contenant du texte (IFS="$IFS")

    Je vais voir ce que je peux faire pour la suite


    Pour tous les autres visiteurs qui lisent ce message, n'hésitez pas à me proposer tout autre indice,aide... que vous estimeriez nécessaire car je suis là pour m'améliorer

  6. #6
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 559
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 559
    Points : 19 399
    Points
    19 399
    Par défaut
    test est une commande interne dont [ est un alias.
    quant à "correspondance", c'est le but même du script : trouver les correspondances entre les données saisies par l'utilisateur et le fichier livres.
    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  7. #7
    Expert éminent sénior Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 251
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 251
    Points : 13 477
    Points
    13 477
    Par défaut
    Bonjour

    Il faut que tu comprennes la différence entre IFS=':'; read toto tata titi et IFS=':' read toto tata titi. Dans le premier cas, tu modifies définitivement l'IFS, puis tu lis les données. Dans le second cas, tu modifies temporairement l'IFS pour la seule commande "read". Ce qui t'évites un IFSold inutile.

    D'autre part, on utilise pas ls dans un script. On préfèrera avantageusement find ou stat selon le besoin.
    Cette réponse vous apporte quelque chose ? Cliquez sur en bas à droite du message.

  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 699
    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 699
    Points : 30 999
    Points
    30 999
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par environnementBash Voir le message
    Je laisse mon script au complet pour mieux visualiser ma démarche, mes commentaires et mes erreurs:
    Ok, voyons ça

    Citation Envoyé par environnementBash Voir le message
    read -p "Quelle catégorie souhaiteriez-vous extraire ?" cat
    Hum... donner à une variable le même nom qu'une commande existante... Un bon moyen de perdre son lecteur...

    Citation Envoyé par environnementBash Voir le message
    while read cat
    Donc la variable "cat" précédemment saisie n'a pas été traitée...
    Citation Envoyé par environnementBash Voir le message
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
           if [[ -z $cat ]]
     
                       then
     
                                   echo
     
                                   echo "ligne contenant un tiret non traitée"
     
                                   continue
     
           fi
    Hum... "-z" demande une chaine vide donc à priori la chaine ne contiendra pas de tiret (sinon elle n'est pas vide). Et là encore (surtout là en fait) il faut quoter la variable. Parce que écrire un test avec une variable vide peut rendre le test bancal. Exemple test $var = "xxx" donnera test = "xxx" si la variable est vide, ce qui rendra la commande syntaxiquement incorrecte, tandis qu'écrire test "$var" = "xxx" donnera test "" = "xxx" si la variable est vide, ce qui donne un test au résultat faux (donc toujours correct du point de vue logique car une chaine vide n'est pas égale à "xxx") mais surtout correctement écrit et donc compréhensible par le shell. Bref le code ne plante pas et donne le bon résultat.
    Dans ce cas précis test -z $cat ça marche parce qu'il se trouve que les tests sur les longueurs de strings (-z, -n) acceptent de ne pas avoir d'opérande ce qui donne une fausse impression de sécurité et surtout donne la mauvaise habitude de ne pas quoter les strings. Pour résumer, sans les quotes ça peut marcher parfois et planter ailleurs, avec les quotes ça marche tout le temps (enfin sauf quand on utilise des opérateurs de comparaison numérique comme "-eq" ou "-ne" ou les autres mais là on fait alors un peu plus attention à ce qu'on écrit)
    Et évite de mettre une ligne vide entre chaque instruction...

    Citation Envoyé par environnementBash Voir le message
    ls -l | head -1 /home/user/livres | cut -d: -f1,4 /home/user/livres
    Alors là...
    Lisons cette instruction ensemble...
    • le liste mon dossier au format long (j'obtiens la liste des fichiers)
    • j'envoie cette liste à la commande "head" qui ne récupère que la première ligne soit d'un fichier s'il lui est donné, soit de l'entrée standard. Comme le fichier lui est donné en paramètre, la commande récupère cette première ligne et ce qui lui vient du "ls" est simplement ignoré
    • j'envoie cette ligne à la commande "cut" qui, pareil que head, ne traite stdin que si elle n'a pas de fichier à traité. Or là elle a un fichier donc ignore ce qui lui vient du pipe

    En dehors du fait que je n'ai absolument aucune idée de ce que tu voulais faire ici, tout ça équivaut simplement à cut -d: -f1,4 /home/user/livres.

    Citation Envoyé par environnementBash Voir le message
    Pour tous les autres visiteurs qui lisent ce message, n'hésitez pas à me proposer tout autre indice,aide...
    Ben en fait je n'ai encore pas bien compris ce que tu dois obtenir au final. J'ai compris que si on demande par exemple "ROMAN" on doit obtenir un fichier nommé "fic.ROMAN" et contenant ceci
    Nom2 (Prénom2) [TITRE2], Nom5 (Prénom5) [TITRE5]
    Nom2 - TITRE2
    Nom5 - TITRE5
    Nb de livres: 2
    Si c'est ça, personnellement j'écrirais une fonction dédiée à récupérer une catégorie précise et à créer le fichier en conséquence, et ensuite j'appellerais la fonction pour chaque catégorie demandée.
    Exemple

    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #!/bin/bash
     
    # La fonction qui extrait une catégorie du fichier qu'on lui donne
    function extractCat() {
    	...
    }
     
    # Traitement de toutes les catégories passées au programme	
    for categorie in "$@"; do
    	extractCat "$categorie" "fic"
    done

    Citation Envoyé par Flodelarab Voir le message
    Dans le second cas, tu modifies temporairement l'IFS pour la seule commande "read". Ce qui t'évites un IFSold inutile.
    Ah, ça je ne savais pas qu'on avait le droit de modifier l'IFS juste pour l'appel à read...
    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
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 559
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 559
    Points : 19 399
    Points
    19 399
    Par défaut
    Citation Envoyé par Sve@r
    Ah, ça je ne savais pas qu'on avait le droit de modifier l'IFS juste pour l'appel à read
    pas seulement l'IFS. N'importe quelle variable (pourvu que son usage soit prévu) peut être définie "localement" pour le seul environnement de n'importe quelle commande.

    prenons pour exemple un script simple :
    Code ./monScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #!/bin/sh
     
    echo "\$maVar = $maVar"
    dans l'environnement courant :
    Code /bin/sh : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $ echo "${maVar:-"\$maVar n'est pas définie"}"
    $maVar n'est pas définie
    $
    on exécute :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $ maVar="foo bar baz" ./monScript
    $maVar = foo bar baz
    $
    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  10. #10
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 101
    Points : 5 849
    Points
    5 849
    Par défaut
    Citation Envoyé par environnementBash Voir le message
    Merci infiniment pour ton commentaire car je me suis rendu compte que j'ai mal expliqué mon objectif que je vais éclaircir...
    Pour éclaircir encore un peu plus, pourrais-tu montrer un exemple du contenu de ce que tu souhaiterais obtenir ?

    Par "contenu", je veux dire un ou deux exemples concrets d'utilisation, avec les paramètres et les sorties résultantes, issues de ta base de données, ou, s'il y a de l'interaction, une trace d'un dialogue fictif entre ton script et un utilisateur (en plus des spécifications/explications que tu as données).

  11. #11
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Flodelarab Voir le message
    Bonjour

    Il faut que tu comprennes la différence entre IFS=':'; read toto tata titi et IFS=':' read toto tata titi. Dans le premier cas, tu modifies définitivement l'IFS, puis tu lis les données. Dans le second cas, tu modifies temporairement l'IFS pour la seule commande "read". Ce qui t'évites un IFSold inutile.

    D'autre part, on utilise pas ls dans un script. On préfèrera avantageusement find ou stat selon le besoin.

    Un énorme merci pour ces précisions, j'en prends bonne note

  12. #12
    Invité
    Invité(e)
    Par défaut
    Un grand merci pour toutes tes commentaires. Je vais essayer d'être le plus précis possible dans cette réponse car j'ai oublié de préciser que je me forme depuis à peine 1 an et j'ai démarré sans 'bases solides'.
    Citation Envoyé par Sve@r Voir le message
    Ok, voyons ça

    Hum... donner à une variable le même nom qu'une commande existante... Un bon moyen de perdre son lecteur...

    Donc la variable "cat" précédemment saisie n'a pas été traitée...
    Il s'agit d'une bête erreur... Je vais essayer de le remplacer par 'categorieChoisie' demain car je serai en congé...

    Hum... "-z" demande une chaine vide donc à priori la chaine ne contiendra pas de tiret (sinon elle n'est pas vide).
    J'avais moi même mal compris ce que je voulais et vous remercie pour vos commentaires. En d'autres termes, j'avais dans un premier temps pensé que je devais créer un fichier spécifique (avec un nom unique) pour chaque personne qui exploite mon script en indiquant la categorie de livres qu'il souhaite visualiser (à partir de read " Quelle catégorie souhaiteriez-vous extraire ?" cat (et que je vais remplacer par categorieChoisie) )

    Je vais montrer un exemple d'un extrait de ce qui se trouve dans le fichier 'livres.txt' et qui est déjà dans mon répertoire (c'est un fichier à plat).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    Nom1:Prénom1:TITRE1:2000:BD
    Nom2:Prénom2:TITRE2:2001:ROMAN
    Nom3:Prénom3:TITRE3:2002:SCIENCES
    Nom4:Prénom4:TITRE4:2003:BD
    Nom5:Prénom5:TITRE5:2004:ROMAN
    Nom6:Prénom6:TITRE6:2004:SCIENCES
    -:-:TITRE7:2004:ROMAN
    et lorsqu'une personne choisit 'ROMAN' par exemple (à partir de read "Quelle catégorie souhaiteriez-vous extraire ?" categorieChoisie), alors il faudra alors créer un fichier (avec un nom unique) pour reprendra la liste de livres qui sera ici pour cet exemple :
    [/CODE]
    Pour la 1re ligne :
    Nom2 Prénom2 TITRE2 2001 Nom5 Prénom5 TITRE5 2004

    Pour la 2e ligne :
    Nom2 TITRE2 - Nom5 TITRE5

    Pour la 3e ligne :
    2
    [/CODE]
    Ces 3 lignes seront enregistrées dans un nouveau fichier (nom au choix).



    Ben en fait je n'ai encore pas bien compris ce que tu dois obtenir au final. J'ai compris que si on demande par exemple "ROMAN" on doit obtenir un fichier nommé "fic.ROMAN"
    Voici comment j'avais mal réfléchi. C'était très bête mais maintenant au-moins je sais ce qui m'avait freiné lors de l'écriture de l'algorithme sur papier... :
    Par exemple, je m'étais dit que il se peut que (je cite des chiffres au hasard) chaque jour au-moins 500 personnes demande la liste de 'ROMAN', au-moins 200 personnes qui demandent 'BD' et au-moins 350 personnes qui demandent 'SCIENCES', où il faudra donc créer (toujours pour cet exemple) au-moins 1150 fichiers chaque jour. chaque fichier ayant un nom unique et spécifique à chaque personne ayant choisi une cat (meme si plusieurs on demandé la meme cat)... Et ainsi de suite pour les jour qui suivent.

    Maintenant, un utilisateur sur un autre forum a eu la gentillesse de m'expliquer hier ce que je n'avais pas saisi. Voici donc ce qu'il me restera à faire demain, il s'agit d'un extrait de sa réponse :

    chacune de ces 500 personnes sera mise dans la liste des personnes associées à l'unique demande nommée ROMAN
    donc, elles vont demander une copie du seul fichier contenant la liste de 'ROMAN'

    chacune de ces 200 personnes sera mise dans la liste des personnes associées à l'unique demande nommée BD
    donc, elles vont demander une copie du seul fichier contenant la liste de 'BD'

    -chacune de ces 350 personnes sera mise dans la liste des personnes associées à l'unique demande nommée SCIENCES
    donc, elles vont demander une copie du seul fichier contenant la liste de 'SCIENCES'

    Finalement il n'y aura que 3 fichiers résultants des 3 demandes

    et il y aura 3 listes de personnes <=> une liste de personnes pour chacune des 3 demandes
    ce qui fera 1050 personnes qui recevront chacune une copie d'un de ces 3 fichiers résultants de ces 3 demandes
    donc, 1050 fichiers de type lien
    Il ne me restera plus qu'à refaire un algorithme pour ensuite enfin pouvoir terminer ce script... Je poserai une nouvelle version de mon script demain (et je l'espère) !

  13. #13
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par jack-ft Voir le message
    Pour éclaircir encore un peu plus, pourrais-tu montrer un exemple du contenu de ce que tu souhaiterais obtenir ?

    Par "contenu", je veux dire un ou deux exemples concrets d'utilisation, avec les paramètres et les sorties résultantes, issues de ta base de données, ou, s'il y a de l'interaction, une trace d'un dialogue fictif entre ton script et un utilisateur (en plus des spécifications/explications que tu as données).
    Bien sûr !
    Comme j'ai répondu à tout le monde en même temps, je vais raccourcir le message #12 pour que tu n'aies pas à tous lire (car la réponse est longue)


    Voici un exemple d'un extrait de ce qui se trouve dans le fichier 'livres.txt' et qui est déjà dans mon répertoire (c'est un fichier à plat).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    Nom1:Prénom1:TITRE1:2000:BD
    Nom2:Prénom2:TITRE2:2001:ROMAN
    Nom3:Prénom3:TITRE3:2002:SCIENCES
    Nom4:Prénom4:TITRE4:2003:BD
    Nom5:Prénom5:TITRE5:2004:ROMAN
    Nom6:Prénom6:TITRE6:2004:SCIENCES
    -:-:TITRE7:2004:ROMAN
    et lorsqu'une personne choisit 'ROMAN' par exemple (à partir de read "Quelle catégorie souhaiteriez-vous extraire ?" categorieChoisie), alors il faudra alors créer un fichier (avec un nom unique) pour reprendra la liste de livres qui sera ici pour cet exemple :

    Pour la 1re ligne :
    Nom2 Prénom2 TITRE2 2001 Nom5 Prénom5 TITRE5 2004

    Pour la 2e ligne :
    Nom2 TITRE2 - Nom5 TITRE5

    Pour la 3e ligne :
    2
    Ces 3 lignes seront enregistrées dans un nouveau fichier (nom au choix).


    Voici comment j'avais mal réfléchi :
    Par exemple, je m'étais dit que il se peut que (je cite des chiffres au hasard) chaque jour au-moins 500 personnes demande la liste de 'ROMAN', au-moins 200 personnes qui demandent 'BD' et au-moins 350 personnes qui demandent 'SCIENCES', où il faudra donc créer (toujours pour cet exemple) au-moins 1150 fichiers chaque jour. chaque fichier ayant un nom unique et spécifique à chaque personne ayant choisi une cat (meme si plusieurs on demandé la meme cat)... Et ainsi de suite pour les jour qui suivent.
    Maintenant, Voici ce qu'il me restera à faire :
    chacune de ces 500 personnes sera mise dans la liste des personnes associées à l'unique demande nommée ROMAN
    donc, elles vont demander une copie du seul fichier contenant la liste de 'ROMAN'

    chacune de ces 200 personnes sera mise dans la liste des personnes associées à l'unique demande nommée BD
    donc, elles vont demander une copie du seul fichier contenant la liste de 'BD'

    -chacune de ces 350 personnes sera mise dans la liste des personnes associées à l'unique demande nommée SCIENCES
    donc, elles vont demander une copie du seul fichier contenant la liste de 'SCIENCES'

    Finalement il n'y aura que 3 fichiers résultants des 3 demandes

    et il y aura 3 listes de personnes <=> une liste de personnes pour chacune des 3 demandes
    ce qui fera 1050 personnes qui recevront chacune une copie d'un de ces 3 fichiers résultants de ces 3 demandes
    donc, 1050 fichiers de type lien
    Il ne me restera plus qu'à refaire un algorithme pour ensuite enfin pouvoir terminer ce script... Je poserai une nouvelle version de mon script demain (et je l'espère) !

  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 699
    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 699
    Points : 30 999
    Points
    30 999
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par environnementBash Voir le message
    et lorsqu'une personne choisit 'ROMAN' par exemple (à partir de read "Quelle catégorie souhaiteriez-vous extraire ?" categorieChoisie), alors il faudra alors créer un fichier (avec un nom unique) pour reprendra la liste de livres
    Généralement on n'aime pas trop les scripts qui posent des questions. On préfère des scripts qui ont tout dès le départ pour travailler, tel que dans mon exemple précédent
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #!/bin/bash
     
    # La fonction qui extrait une catégorie du fichier qu'on lui donne
    function extractCat() {
    	...
    }
     
    # Traitement de toutes les catégories passées au programme	
    for categorie in "$@"; do
    	extractCat "$categorie" "fic"
    done
    On l'appelle en lui passant par exemple "ROMAN" et "BD" et il génère directement "fic.ROMAN" et "fic.BD".
    Mais bon, vu que c'est la fonction "extractCat" qui fait tout, rien n'interdit aussi de faire saisir la catégorie et la lui passer.

    Citation Envoyé par environnementBash Voir le message
    Pour la 1re ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Nom2 Prénom2 TITRE2 2001 Nom5 Prénom5 TITRE5 2004
     
    Pour la 2e ligne :
    Nom2 TITRE2 - Nom5 TITRE5
    On peut voir qu'en réalité il n'y a absolument AUCUNE différence entre la première ligne et la seconde. Toutes les deux affichent l'ensemble des romans avec leurs auteurs sur une ligne
    Je pensais plutôt à un résultat ainsi
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Nom2 (Prénom2) [TITRE2], Nom5 (Prénom5) [TITRE5]
    Nom2 - TITRE2
    Nom5 - TITRE5
    Nb de livres: 2
    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
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    On peut voir qu'en réalité il n'y a absolument AUCUNE différence entre la première ligne et la seconde. Toutes les deux affichent l'ensemble des romans avec leurs auteurs sur une ligne
    Je pensais plutôt à un résultat ainsi
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Nom2 (Prénom2) [TITRE2], Nom5 (Prénom5) [TITRE5]
    Nom2 - TITRE2
    Nom5 - TITRE5
    Nb de livres: 2
    Je comprends parfaitement votre point de vue. Autant pour moi, j'ai du avoir mal interpréter la consigne.
    Je n'avais malheureusement pas eu le temps de recopier toute la consigne le jour de la consultation de la copie de cette exercice car j'ai du écrire à la main sur papier une consigne qui était longue... Néanmoins, j'ai écris à partir de la moitié car le début expliquait simplement les champs, le contenu de livres.txt et que l'utilisateur devra dire quelle catégorie de livre il veut que le script extrait pour lui...

    voici ce que j'ai (c'est une phrase qui fait 8 lignes car je devais écrire vite...) :
    D’abord, je vérifie si livres.txt existe bel et bien dans mon rep personnel car juste après ça je dois demander à l'utilisateur quelle catégorie il veut extraire pour ensuite pouvoir réaliser l'extraction des livres qui correspondent à la catégorie choisie par la personne et puis je dois compter le nb de livres extraits, et à la fin je devrai être capable de créer un fichier où :
    la 1re ligne renvoie une liste des auteurs et les titres de la catégorie x
    les lignes qui suivent indiquera le nom ‘’ - ‘’le titre de la catégorie x
    la dernière ligne indiquera le nb de livres (y)
    pour afficher à l'écran le contenu du fichier que je viens de créé
    Cela étant dit, je pense que vous avez raison concernant l'apparence que devrait avoir le résultat.

  16. #16
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 559
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 559
    Points : 19 399
    Points
    19 399
    Par défaut
    Citation Envoyé par Sve@r
    Généralement on n'aime pas trop les scripts qui posent des questions. On préfère des scripts qui ont tout dès le départ pour travailler
    et, sinon ? on fait échouer le script avec un message d'erreur, ou on préfère qu'il demande les instructions dont il a besoin ? ce qui n'empêche pas d'émettre un rappel sur la "syntaxe" du script.
    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  17. #17
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 699
    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 699
    Points : 30 999
    Points
    30 999
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par environnementBash Voir le message
    Cela étant dit, je pense que vous avez raison concernant l'apparence que devrait avoir le résultat.
    Quelque chose me dit que tu ne vas pas y arriver, je pense par manque d'habitude. Je trouve aussi que c'est pas un exo super facile quand on débute. Ok il correspond bien à ce qu'on peut avoir besoin de faire en shell mais nécessite déjà d'être quand-même bien à l'aise.

    Et puis je vois que tu t'accroches donc j'ai décidé de te donner un coup de pouce
    Code bash : 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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    #!/bin/bash
    # Usage : programme categorie1 [categorie2 ...]
     
    # Fonction chargée d'extraire la catégorie demandée
    function extractCat() {
    	# Création de la première ligne
    	firstLig=""
    	while read ligne; do
    		nom="$(echo "$ligne" |cut -f1 -d:)"
    		prenom="$(echo "$ligne" |cut -f2 -d:)"
    		titre="$(echo "$ligne" |cut -f3 -d:)"
    		firstLig="$firstLig, $nom ($prenom) [$titre]"
    	done <<< $(grep ":$1$" "$2")
     
    	# Création du fichier final
    	(
    		# Première ligne
    		echo "$firstLig" |cut -c3-	# Pour supprimer la première virgule
     
    		# Les lignes contenant la catégorie demandée
    		cpt=0
    		while read ligne; do
    			cpt=$((cpt+1))
    			nom="$(echo "$ligne" |cut -f1 -d:)"
    			titre="$(echo "$ligne" |cut -f3 -d:)"
    			echo "$nom - $titre"
    		done <<< $(grep ":$1$" "$2")
     
    		# Nb de livres
    		echo "Nb de livres: $cpt"
    	) > "$2.$1"
     
    	echo "Création $2.$1 terminée"
    }
     
    for categorie in "$@"; do
    	extractCat "$categorie" "livres.txt"
    done
    J'avais d'abord fait une version utilisant les tableaux comme j'avais conseillé dans mon premier post puis je me suis dit que faire deux fois le grep c'était pas catastrophique. Après ça peut toujours se changer, suffit de remplir le tableau dans la première boucle et donc le traiter dans la seconde.

    M'étant plus consacré à un autre langage ces dernières années j'ai pas trop suivi les évolutions du shell et je n'ai peut-être pas forcément utilisée ses dernières technos (je ne savais même pas qu'on peut créer une variable spécifique à un process) mais au-moins c'est un shell assez simple à lire.
    Il fonctionne à partir d'un fichier formaté ainsi
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Nom1:Prénom1:TITRE1:2000:BD
    Nom2:Prénom2:TITRE2:2001:ROMAN
    Nom3:Prénom3:TITRE3:2002:SCIENCES
    Nom4:Prénom4:TITRE4:2003:BD
    Nom5:Prénom5:TITRE5:2004:ROMAN
    Nom6:Prénom6:TITRE6:2004:SCIENCES
    Evidemment il gagnerait à être optimisé (ne lire par exemple qu'une fois le fichier et gérer les différentes catégories demandées au fur et à mesure) mais bon, c'est pas non plus le truc de l'année
    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]

  18. #18
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 101
    Points : 5 849
    Points
    5 849
    Par défaut
    Citation Envoyé par Flodelarab Voir le message
    Il faut que tu comprennes la différence entre IFS=':'; read toto tata titi et IFS=':' read toto tata titi. Dans le premier cas, tu modifies définitivement l'IFS, puis tu lis les données. Dans le second cas, tu modifies temporairement l'IFS pour la seule commande "read". Ce qui t'évites un IFSold inutile.
    Merci Flodelarab pour cette intervention. J'avais déjà vu ça plusieurs fois... sans bien comprendre pleinement.

    Du coup, j'ai fait un test avec une autre variable pour voir et comprendre mieux (car trouver l'explication précise dans le "man bash" n'est pas chose simple (pour moi)):
    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
    $ echo $A
     
    $ A=3 echo "$A"
     
    $ foo(){ echo "$A"; }
     
    $ A=3 foo
    3
     
    $ foo
     
    $ A=2; A=3 echo $A
    2
     
    $ A=3 foo
    3
     
    $ A=3 echo $A
    2
     
    $ A=3 foo; foo
    3
    2
    J'en déduis que:
    • lorsqu'une "instruction" est précédée d'une affectation non suivie d'un ";", cette affectation fait grosso modo partie de l'instruction
    • cette affectation ne concerne que cette instruction (donc jusqu'au prochain ";" ou la fin de ligne)
    • la variable retrouve sa valeur après le ";" (ou la fin de ligne), come si elle était locale à l'instruction dont elle fait partie.
    • dans l'instruction courante, tout se passe comme si la variable "$A" était expansée AVANT son affectation, ce qui fait que A=3 echo $A est expansé en A=3 echo 2 avant que A=3 ne soit effectuée, et donc va afficher "2" (même si le echo 2 est effectué après l'affectation)
    • dans A=3 foo, l'affectation A=3 est effectuée avant l'appel de "foo" qui expanse "$A" en sa valeur courante (et locale), à savoir "3".

  19. #19
    Expert éminent sénior Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 251
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 251
    Points : 13 477
    Points
    13 477
    Par défaut
    Citation Envoyé par jack-ft Voir le message
    Encore un piège de la programmation bash. Merci de l'avoir souligné.
    Cette réponse vous apporte quelque chose ? Cliquez sur en bas à droite du message.

  20. #20
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 298
    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 298
    Points : 12 778
    Points
    12 778
    Par défaut
    Citation Envoyé par jack-ft Voir le message
    J'en déduis que:
    • lorsqu'une "instruction" est précédée d'une affectation non suivie d'un ";", cette affectation fait grosso modo partie de l'instruction
    • cette affectation ne concerne que cette instruction (donc jusqu'au prochain ";" ou la fin de ligne)
    • la variable retrouve sa valeur après le ";" (ou la fin de ligne), come si elle était locale à l'instruction dont elle fait partie.
    • dans l'instruction courante, tout se passe comme si la variable "$A" était expansée AVANT son affectation, ce qui fait que A=3 echo $A est expansé en A=3 echo 2 avant que A=3 ne soit effectuée, et donc va afficher "2" (même si le echo 2 est effectué après l'affectation)
    • dans A=3 foo, l'affectation A=3 est effectuée avant l'appel de "foo" qui expanse "$A" en sa valeur courante (et locale), à savoir "3".
    Et pour en rajouter une couche, tu peux définir plusieurs variables uniquement pour la dite commande comme par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $ foo(){ echo "$YY et $xx" ;}
    $ xx=0 YY=/tmp foo
    /tmp et 0
    Cordialement.

Discussions similaires

  1. [XL-2010] Extraire des lignes d'une colonne situées entre 2 mots constants
    Par xico8 dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 03/02/2015, 10h07
  2. Extraire des lignes avec une formule
    Par maxxxime dans le forum Excel
    Réponses: 9
    Dernier message: 15/06/2010, 17h05
  3. [XL-2007] Extraire des lignes en fonction d'une valeur de cellule dans un autre fichier
    Par MisterTambo dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 19/08/2009, 10h42
  4. Réponses: 3
    Dernier message: 21/01/2009, 13h49
  5. Extraire des lignes d'un fichier en commande bash
    Par newnew dans le forum Linux
    Réponses: 3
    Dernier message: 27/07/2004, 16h22

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