Python 3 liste avec [b""\n"]

xunil2003 Messages postés 766 Date d'inscription   Statut Membre Dernière intervention   -  
mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   -

Bonjour,

Je récupère le retour d'une commande shell dans une liste :

import subprocess
process = subprocess.Popen([e1, e2, e3, e4], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) #"ls -alh /dev"
liste_retour = process.stdout.readlines()
print ("liste_retour : ",liste_retour)
if not liste_retour:
    print ("Im an error")
    err = process.stderr.readlines()
    print('ERROR: {}'.format(err))
    liste_retour = []
    liste_retour.append(format(err))
    print("liste_retour : ",liste_retour)
else:
     print ("I'm a success")
     print("liste_retour : ",liste_retour)

for idex, retour in enumerate(liste_retour):
        text_box.insert(tk.END, retour) 

La commande shell me retourne en console

Im an error
ERROR: [b"/usr/bin/rm: impossible de supprimer '/home/utilisateur': Aucun fichier ou dossier de ce type\n"]
liste_retour[0] :  [b"/usr/bin/rm: impossible de supprimer '/home/utilisateur': Aucun fichier ou dossier de ce type\n"]

et dans la fenêtre retour avec le text_box, il s'affiche

[b"/usr/bin/rm: impossible de supprimer '/home/utilisateur': Aucun fichier ou dossier de ce type\n"]

Comment afficher la liste correctement sans le [b" et "\n"] ?

Merci d'avance pour vos conseils et avis
Linux / Firefox 124.0

8 réponses

  1. hih
     

    Bonsoir.

    Le b indique que c'est un bytes.

    Ce qu'on peut voir en affichant le type.

    print(type(liste_retour[0]))

    Pour transformer en str, il faut se servir de la méthode decode de bytes.

    Et pour le \n de fin, bah avec str.strip, str.rstrip.

    0
  2. xunil2003 Messages postés 766 Date d'inscription   Statut Membre Dernière intervention   14
     

    bonsoir,

    Pourtant quand j'utilise décode()

    retour_decode = str(m).decode('utf-8')
    print(type("retour_decode : ",retour_decode))

    retour

    File "/home/laurent/Langages/python/3.4.3/Gestion-des-utilisateurs-et-groupes/Gdueg-02.py", line 936, in valider_fenetre_supprimer_le_repertoire_personnel_d_un_utilisateur
        retour_decode = str(m).decode('utf-8')
    AttributeError: 'str' object has no attribute 'decode'

    et avec

    print ("type(m) : ",type(m))
    retour_decode = bytes(m, 'utf-8')
    print("type(retour_decode) : ",type(retour_decode))
    print("retour_decode : ",retour_decode)

    le retour

    type(m) :  <class 'str'>
    type(retour_decode) :  <class 'bytes'>
    retour_decode :  b'[b"/usr/bin/rm: impossible de supprimer \'/home/utilisateur\': Aucun fichier ou dossier de ce type\\n"]'
    

    Je tourne en rond, encore ['b' dans la liste.
     

    Merci.

    0
  3. hih
     

    Forcément, tu convertis ton bytes en str, il faut simplement utiliser decode sur le bytes, puisque c'est une méthode de cette classe.

    import subprocess
    process = subprocess.Popen(
        ['ls', '-alh', '/dev'],
        shell=False,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )
    liste_retour = process.stdout.readlines()
    print(len(liste_retour))
    print(type(liste_retour[-1]))
    
    print(liste_retour[-1].decode()) # str

    Qui par ex. me retourne

    188
    <class 'bytes'>
    crw-rw-rw-   1 root root      1,     5 mars  21 19:27 zero
    0
  4. xunil2003 Messages postés 766 Date d'inscription   Statut Membre Dernière intervention   14
     

    Re,

    Je ne comprends pas avec

    print ()
    import subprocess
    process = subprocess.Popen([e1, e2, e3, e4], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
    liste_retour = process.stdout.readlines()
    print ("liste_retour : ",liste_retour)
    if not liste_retour:
        print ("Im an error")
        err = process.stderr.readlines()
        print('ERROR: {}'.format(err))
        liste_retour = []
        #liste_retour.append('ERROR:{}'.format(err))
        liste_retour.append(format(err))
        print("liste_retour : ",liste_retour)
            
            
        print("len(liste_retour) : ",len(liste_retour))
        print ()
        print("type(liste_retour) : ",type(liste_retour))
        #print("liste_retour.decode() : ",liste_retour.decode()) # str
        print ()
        print("type(liste_retour[-1]) : ",type(liste_retour[-1]))
        print("liste_retour[-1].decode() : ",liste_retour[-1].decode()) # str
    else:
        print ("I'm a success")
        print("liste_retour : ",liste_retour)

    retour :

      File "/home/laurent/Langages/python/3.4.3/Gestion-des-utilisateurs-et-groupes/Gdueg-02.py", line 1008, in valider_fenetre_supprimer_le_repertoire_personnel_d_un_utilisateur
        print("liste_retour[-1].decode() : ",liste_retour[-1].decode()) # str
    AttributeError: 'str' object has no attribute 'decode

    idem avec liste_retour.decode()

    Y a un problème avec decode ?

    Merci.

    0
    1. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588
       

      decode() fonctionne bien.

      import subprocess
      process = subprocess.Popen("kmd 'dyr' -c", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
      liste_retour = process.stdout.readlines()
      if not liste_retour:
          err = process.stderr.readlines()
          liste_retour=[]
          for l in err:
              liste_retour.append(l.decode())
      for  retour in liste_retour:
          print("+", retour)
      
      0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. Phil_1857
     

    Bonjour, 

    et ça, ça affiche quoi : 

    print("type(liste_retour[-1]) : ",type(liste_retour[-1]))

    est-ce que ça affiche

    <class 'bytes'>  comme ça le devrait ????

    0
  7. hih
     

    Salut.

    Le code que je t'ai mis n'est pas à utiliser au cas où il y a une erreur.

    Mais c'est de toute façon la même chose, je ne comprends pas ce que tu fais.

    Ton code si tu veux ajouter l'erreur à la liste devrait se résumer à :

    import subprocess
    
    process = subprocess.Popen(['ls', 'hih'], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
    liste_retour = process.stdout.readlines()
    if not liste_retour:
        err = process.stderr.readlines()
        print('err', type(err), len(err), type(err[0])) # err <class 'list'> 1 <class 'bytes'>
        liste_retour.append(f'ERROR: {err[0].decode().rstrip()}')
        print("liste_retour : ", liste_retour)
    else:
        print ("I'm a success")
        print("liste_retour : ", liste_retour)

    Qui donc afficherait : liste_retour :  ["ERROR: ls: impossible d'accéder à 'hih': Aucun fichier ou dossier de ce type"]
     

    Je pense que tu cherches compliqué, alors que c'est très simple ^^

    0
  8. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   Ambassadeur 1 588
     

    bonjour,

    err = process.stderr.readlines()
    m = ""
    for l in err:
        m += l.decode()
    print(m)
    0
  9. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 940
     

    Bonjour

    Quelques explications préalables

    subprocess n'a pas d'a priori sur la nature des caractères retournés par un processus, et voit donc le flux retourné comme une suite d'octet. Il y a une raison technique à ça : certaines commandes retourne un flux binaire, pas un flux texte. Il t'appartient donc de reconvertir ce flux en caractère si le besoin s'en fait sentir.

    Tant qu'on est dans l'encodage, si tu te demandes lequel utiliser, je te recommande d'utiliser partout et autant que possible de l'UTF-8 dans toutes les situations (c'est ce qui est fait de nos jours par défaut sous Linux et c'est un bon choix).

    Concernant l'appel à un sous-processus, il faut vérifier s'il est en erreur ou pas pour savoir s'il s'est bien déroulé ou non. Par convention, un programme qui se termine bien retourne 0, une valeur non nulle sinon. En shell tu peux vérifier le code de retour de la dernière commande en affichant la valeur de $?.

    Exemple :

    cat /etc/fstab > /dev/null; echo $?   # Fonctionne, affiche 0
    cat /etc/shadow > /dev/null; echo $?  # Échoue, affiche 1
    

    De plus, un processus affiche ses résultats dans deux flux (soit stdout, soit stderr) ce qui correspond en shell aux redirections :

    • 1>, 1>> (ou en abrégé : > et >>) pour stdout
    • 2>, 2>> pour stderr

    Cela signifie que quand tu appelles un sous processus, tu dois potentiellement rattraper ces deux flux.

    Retour à python

    Voici comment appeler un processus en python

    from subprocess import Popen, PIPE
    
    def run(
        cmd: list,
        stdin_data: bytes | None = None,
        decode: bool = True,
        encoding: str = "UTF-8"
    ) -> bytes | str:
        """
        Run a shell command.
    
        Args:
            cmd (list): The words involved in the shell command.
            stdin_data (bytes | None): Data passed to the command
                from ``stdin``.
            decode (bool): Pass ``True`` to encode the data passed to
                the subprocess and to decode the data received
                from the subprocess.
            encoding (str | None): Encoding used to decode the bytes.
        """
        proc = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
        (stdout_data, stderr_data) = proc.communicate(
            stdin_data.encode(encoding) if stdin_data else None
        )
        status = proc.wait()
        if status == 0:
            if decode:
                return stdout_data.decode(encoding)
            else:
                return stdout_data
        else:
            raise RuntimeError(
                f"{' '.join(cmd)} exit code: {status}\n"
                "[==== stderr ====]\n"
                f"{stderr_data.decode(encoding)}\n"
            )
    
    # ls -la /
    ls = run(["ls", "-la", "/"])
    print(ls)
    
    # ... | grep root
    grep = run(["grep", "root"], stdin_data=ls)
    print(grep)
    
    # cat /etc/shadow
    cat = run(["cat", "/etc/shadow"])  # Raise RuntimeError

    Bonne chance

    0