Forum Flightgear France

Une communauté prend son envol

Vous n'êtes pas identifié(e).

Annonce

Futur nouvel inscrit, tu dois au préalable lire l'intégralité des 10 articles des règles, s'il te plaît. Tout nouveau compte qui ne respecte pas les règles sera supprimé par l'administration.

#1 28/08/2020 11:30:16

Clm76
Membre
Lieu : LFOH - LFOY
Inscription : 22/10/2012
Messages : 1 632

[RESOLU] Scripts bash

Hello les spécialistes des scripts, je pense notamment à ctesc356. smile

Comment est-il possible de traiter une ligne composée dans un script bash ?
Exemple avec un fichier de dates d'anniversaire :

12-04-1948 Christian Le Moigne
....

Je n'ai pas de problème avec la date pour en sortir un âge, mais c'est avec l'ensemble "nom prénom" qui comporte un blanc entre le nom et le prénom et avec le nom qui comporte également un blanc que j'ai des problèmes. Je voudrais que le résultat ressorte comme, par exemple :

Anniversaire aujourd'hui : Christian Le Moigne

Merci pour vos conseils.

Dernière modification par Clm76 (6/09/2020 19:16:12)


Fg 2020.4.0 - Linux Mint 21.3 Victoria - Cinnamon et Mate en dual boot - CM Asus P8H67 MLE - CPU i7 3770K - 12 Go Ram - Nvidia Geforce GTX 1660TI - Driver Nvidia 525
+ Hp notebook-15 - Linux Mint 21.3 Victoria -  CPU i3-7020u - Ram 4Go - Intel Graphics 620.

Hors ligne

#2 28/08/2020 13:52:25

rominet
Membre
Inscription : 23/03/2019
Messages : 186

Re : [RESOLU] Scripts bash

Bonjour,

Avec Bash, tu peux utiliser le built-in read:

#! /bin/bash

while read -r date nom; do
    printf "Anniversaire aujourd'hui : %s\n" "$nom"
done

Ici, la lecture se fait depuis l'entrée standard, ce qui est pratique pour enchaîner les commandes au sein de pipelines :

./nom-du-script < fichier_de_données

ou

... | ./nom-du-script

mais tu peux lire depuis un fichier en ajoutant une redirection après le 'done' :

while read -r date nom; do
    printf "Anniversaire aujourd'hui : %s\n" "$nom"
done < /chemin/vers/fichier/de/données       # ou bien, p. ex. < "$1"

Ceci dit, si ton script n'est pas bourré d'appels de commandes, je conseillerais plutôt Python car la programmation en langages shell Bash & Co devient vite pénible dès qu'on veut faire des choses un chouilla plus compliquées ou générales. En lisant encore les données depuis l'entrée standard, on peut faire :

#! /usr/bin/env python3

import sys

for line in sys.stdin:
    date, nom = [ champ.strip() for champ in line.split(' ', maxsplit=1) ]
    print("Anniversaire aujourd'hui : {}".format(nom))

Ici, on enlève le \n de fin de ligne et d'éventuels espaces, tabulations, etc. au début et à la fin de chaque champ avant de le traiter (c'est le but du strip()).


Debian GNU/Linux, driver libre pour carte Radeon HD 4670, FG 'next', 8 Go de RAM

Hors ligne

#3 28/08/2020 14:04:10

ctesc356
Membre
Inscription : 18/05/2010
Messages : 3 483

Re : [RESOLU] Scripts bash

J'aurais trouvé... mais beaucoup plus compliqué wink on reconnaît le maître...

je conseillerais plutôt Python

pareil, dans Python il existe moult fonctions et librairies pour triturer des chaînes dans tous les sens.


Intel i5-9400F, 16Go Ram, Nvidia GTX1660Ti, Linux Mint

Hors ligne

#4 28/08/2020 14:09:31

zakharov
Membre historique du forum.
Inscription : 11/09/2005
Messages : 958

Re : [RESOLU] Scripts bash

Salut,

je pense que sed serait ton ami ici

echo anniversaire(s) du jours: $(sed -n 's/^[0-9]* //p' < ton_fichier_avec_les_dates_et_noms)

On pourrait faire un truc un peu plus évolué pour mettre les données dans un tableau (nom+prénom dans chaque case) histoire de voir s'il y en a plus d'un et afficher l'anniversaire du jour que si il y en a et mettre anniversaire au pluriel si nécessaire:

declare -a anniv_du_jour
eval echo $(sed -rn 's/^[0-9-]* (.+)$/anniv_du_jour[${#anniv_du_jour[@]}="\1";/p' < ton_fichier_avec_les_dates_et_noms)
if test ${#anniv_du_jour[@]} -gt 0; then
    print anniversaire
    test ${#anniv_du_jour[@]} -gt 1 && print s
    echo " du jour:"
    for ((i=0; i<${#anniv_du_jour[@]}; i++)); do
        echo ${anniv_du_jour[i]}
     done
fi

pas testé, écrit à la volée, mais c'est l'idée

@+
bons vols
zakh

Dernière modification par zakharov (28/08/2020 14:11:24)


le zkv1000
Debian Bookworm sur i7-9750H, 16G, NV GeForce GTX 1660 Ti MaxQ 6Go
FG next compilé à la mano
Joystick TM T. Stick X avec fichier de conf perso

Hors ligne

#5 28/08/2020 14:43:25

f-toro
Administrateur
Lieu : LFLA
Inscription : 16/12/2007
Messages : 3 015

Re : [RESOLU] Scripts bash

ctesc356 a écrit :

on reconnaît le maître...

+ 1

Sûr que sur ce plan rominet c'est un bon.

Mais zakh pas mauvais du tout non plus.
Dans la passé, dans signature, il y avait un lien, "les scripts de zakh" !
Et il y en avait un paquet !

big_smile


André. anciennement taureau89_9
Debian Testing Amd64. CM Sabertooth 990FX, FX8350, 32 Go Ram DDR3 1866 Mhz, GTX 1060 6Go, DD 2To Sata 3, THRUSTMASTER T.Flight StickX, FG 2020.4.0 Git.

Hors ligne

#6 28/08/2020 16:05:52

zakharov
Membre historique du forum.
Inscription : 11/09/2005
Messages : 958

Re : [RESOLU] Scripts bash

f-toro a écrit :

Dans la passé, dans signature, il y avait un lien, "les scripts de zakh" !

'Sont toujours là au moins en partie wink de qualité variable bien sûr.

D'ailleurs y en a un tout nouveau pour faire une bdd des appareils de FGaddons et suivre les maj avec un fgfs --update-fgaddon (pas fini y a un soucis avec les dates de dernière maj), et d'ailleurs le script qui gère fgfs permet de vérifier si la révision git de SG/FG passe la compile sur Jenkins de FG

@+
bons vols
zakh


le zkv1000
Debian Bookworm sur i7-9750H, 16G, NV GeForce GTX 1660 Ti MaxQ 6Go
FG next compilé à la mano
Joystick TM T. Stick X avec fichier de conf perso

Hors ligne

#7 28/08/2020 17:58:48

Clm76
Membre
Lieu : LFOH - LFOY
Inscription : 22/10/2012
Messages : 1 632

Re : [RESOLU] Scripts bash

Waouh !!! Merci à tous, je vais étudier cela de plus près ... pour me détendre un peu du nasal et CX. wink

Je débute en bash et ne connais pas python mais je vais quand même y jeter un coup d’œil pour voir ce que ça dit. Merci encore smile smile smile


Fg 2020.4.0 - Linux Mint 21.3 Victoria - Cinnamon et Mate en dual boot - CM Asus P8H67 MLE - CPU i7 3770K - 12 Go Ram - Nvidia Geforce GTX 1660TI - Driver Nvidia 525
+ Hp notebook-15 - Linux Mint 21.3 Victoria -  CPU i3-7020u - Ram 4Go - Intel Graphics 620.

Hors ligne

#8 28/08/2020 18:16:19

f-toro
Administrateur
Lieu : LFLA
Inscription : 16/12/2007
Messages : 3 015

Re : [RESOLU] Scripts bash

Oui, sauf que chez moi le premier des trois liens ne donne rien.

Chemin_de_seb.lautre.net_a_completer .


André. anciennement taureau89_9
Debian Testing Amd64. CM Sabertooth 990FX, FX8350, 32 Go Ram DDR3 1866 Mhz, GTX 1060 6Go, DD 2To Sata 3, THRUSTMASTER T.Flight StickX, FG 2020.4.0 Git.

Hors ligne

#9 6/09/2020 17:16:49

Clm76
Membre
Lieu : LFOH - LFOY
Inscription : 22/10/2012
Messages : 1 632

Re : [RESOLU] Scripts bash

Bonjour à tous,

clm76 a écrit :

Je débute en bash et ne connais pas Python mais je vais quand même y jeter un coup d’œil pour voir ce que ça dit.

Finalement, j'ai écrit mon programme de rappel de dates d'anniversaire en Python (version 3). Il interroge un fichier .txt (Anniv.txt) dont les lignes sont de la forme :

jj-mm-aaaa:Prénom Nom

exemple : 12-04-1996:Ann Le Clem

Le programme est appelé à chaque démarrage de l'ordi et renvoie, pendant 20s une notification lorsque la ou les dates d'anniversaire sont dans les 8 jours.
Le programme :

#! /usr/bin/python3
# coding: utf-8

# Christian Le Moigne - sept 2020

import os,time
from datetime import date
annivFile=os.getenv('HOME')+'/Documents/Anniversaires/Anniv.txt'
today=time.strftime('%d-%m')
td=date.today()
msg=""
with open(annivFile,"r") as fichier:
    for line in fichier:
        line=line.split(':')
        d1, m1, y1 = [int(x) for x in line[0].split('-')]
        anniv=date(td.year, m1, d1)
        diff=(anniv-td).days        
        age=td.year-y1
        if today in line[0]:
            msg+="Aujourd\'hui : "+line[1].rstrip()+" - "+str(age)+" ans \n\n"
        if diff == 1:
            msg+="Demain : "+line[1].rstrip()+" - "+str(age)+" ans \n\n"
        if diff < 8 and diff > 1:
            msg+="Dans "+str(diff)+" jours : "+line[1].rstrip()+" - "+str(age)+" ans \n\n"
    if msg !="":
        title="Anniversaires"
        os.system('notify-send -t 20000 -i face-smile "'+title+'" "<b>'+msg+'</b>"')
        msg=""

La notification :

captur14.png


Fg 2020.4.0 - Linux Mint 21.3 Victoria - Cinnamon et Mate en dual boot - CM Asus P8H67 MLE - CPU i7 3770K - 12 Go Ram - Nvidia Geforce GTX 1660TI - Driver Nvidia 525
+ Hp notebook-15 - Linux Mint 21.3 Victoria -  CPU i3-7020u - Ram 4Go - Intel Graphics 620.

Hors ligne

#10 6/09/2020 20:46:18

f-toro
Administrateur
Lieu : LFLA
Inscription : 16/12/2007
Messages : 3 015

Re : [RESOLU] Scripts bash

On va finir par tout savoir sur la famille ! big_smile


André. anciennement taureau89_9
Debian Testing Amd64. CM Sabertooth 990FX, FX8350, 32 Go Ram DDR3 1866 Mhz, GTX 1060 6Go, DD 2To Sata 3, THRUSTMASTER T.Flight StickX, FG 2020.4.0 Git.

Hors ligne

#11 7/09/2020 0:24:06

rominet
Membre
Inscription : 23/03/2019
Messages : 186

Re : [RESOLU] Scripts bash

C'est pas mal, pour un début. Pour plus de lisibilité, je conseillerais de mettre un espace avant et après le = de l'affectation, +=, ==, + (en gros, les opérateurs binaires). En revanche, je n'en mets pas autour du = pour un argument nommé (comme le maxplit=1 de mon exemple). Et surtout, tu (Clm76) pourrais te débarasser d'os.system() au profit de fonctions du module subprocess. Exemple au tout début de la doc. :

>>> subprocess.run(["ls", "-l"])  # doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)

Tu passes une liste d'arguments au lieu de passer une unique chaîne de caractères. Les listes sont hyper faciles à manipuler avec Python, donc c'est tranquille. Côté avantages :
- Ça ne lance pas un processus shell inutile ;
- Surtout, ça rend ton programme beaucoup plus robuste. En effet, comme une commande shell est une bête chaîne de caractères, il y a plein de caractères spéciaux : espace, \n, >, < &, |, ;, $, ", ', \... et cela pose problème si les arguments insérés dynamiquement dans ta commande contiennent certains d'entre eux. Il faut « échapper » les caractères spéciaux, mais c'est chiant (il y a cependant un module qui le fait : shlex) et totalement inutile. Avec l'autre approche, chaque argument de ta commande est un élément de la liste ; il est passé tel quel à l'appel système sous-jacent (tel qu'execvp() ou execvpe()), terminé. On peut aussi construire des pipelines sans passer par le shell (en faisant justement comme un shell).

Ici, pas de réel problème a priori, mais pour du code lancé avec des données non sûres (p. ex. exécuté comme script CGI pour un site Web, ou bien un progamme ayant accès à une ressource partagée et utilisé par tout un campus, etc.), l'utilisation de os.system() est extrêmement dangereuse (il est souvent très facile de fabriquer des arguments destinés à provoquer une exécution de code arbitraire grâce à $(...) ou quelque chose du genre).

J'ai mon script du même style qui regarde aussi /var/mail/$user, mais je n'utilise pas notify-send. J'utilise genmon pour la partie interface utilisateur (applet pour XFCE très personnalisable via scripting). C'est pas mal, mais sans doute moins visible ; il m'arrive de rater les anniversaires. neutral


Debian GNU/Linux, driver libre pour carte Radeon HD 4670, FG 'next', 8 Go de RAM

Hors ligne

#12 8/09/2020 10:34:02

Clm76
Membre
Lieu : LFOH - LFOY
Inscription : 22/10/2012
Messages : 1 632

Re : [RESOLU] Scripts bash

rominet a écrit :

Et surtout, tu (Clm76) pourrais te débarasser d'os.system() au profit de fonctions du module subprocess.

Merci pour tes conseils. J'ai modifié en conséquence mon fichier.
J'ai aussi modifié le mode d'affichage (passage en critical) pour que la notification reste affichée jusqu'à sa fermeture manuelle, sinon elle disparaît au bout de 5 secondes.
A noter que, chez moi, notify-send -t 20000 par exemple (20 secondes d'affichage) ne fonctionne pas.

Le nouveau code :

#! /usr/bin/python3
# coding: utf-8

# Christian Le Moigne - sept 2020

import subprocess,datetime,time
from datetime import date
annivFile = '/home/chris/Documents/Anniversaires/Anniv.txt'
today = time.strftime('%d-%m')
td = date.today()
title = "Anniversaires"
msg = ""
with open(annivFile,"r") as file:
  for line in file:
    line = line.split(':')
    d1, m1, y1 = [int(x) for x in line[0].split('-')]
    anniv = date(td.year, m1, d1)
    diff = (anniv-td).days        
    age = td.year-y1
    if today in line[0]:
        msg+="Aujourd\'hui : "+line[1].rstrip()+" - "+str(age)+" ans \n\n"
    if diff == 1:
        msg+="Demain : "+line[1].rstrip()+" - "+str(age)+" ans \n\n"
    if diff < 8 and diff > 1:
        msg+="Dans "+str(diff)+" jours : "+line[1].rstrip()+" - "+str(age)+" ans \n\n"

  if msg != "":
    subprocess.run(['notify-send','-u', 'critical', title, '<b>'+msg+'</b>'])
    msg = ""

Fg 2020.4.0 - Linux Mint 21.3 Victoria - Cinnamon et Mate en dual boot - CM Asus P8H67 MLE - CPU i7 3770K - 12 Go Ram - Nvidia Geforce GTX 1660TI - Driver Nvidia 525
+ Hp notebook-15 - Linux Mint 21.3 Victoria -  CPU i3-7020u - Ram 4Go - Intel Graphics 620.

Hors ligne

Pied de page des forums