Contenu | Rechercher | Menus

Annonce

Si vous rencontrez des soucis à rester connecté sur le forum (ou si vous avez perdu votre mot de passe) déconnectez-vous et reconnectez-vous depuis cette page, en cochant la case "Me connecter automatiquement lors de mes prochaines visites".
Test de l'ISO d'Ubuntu francophone : nous avons besoin de testeurs pour la version francophone d'Ubuntu 14.04. Liens et informations ici.

Attention, une faille de sécurité dans bash a récemment été rapportée, il est recommandé de mettre à jour son système (plus de détails)

#1 Le 06/01/2013, à 21:55

Pierre Thibault

Comment fonctionnent les pipes et les commandes shell avec Python

Bonjour,

J'ai de la difficulté à comprendre comment les redirections fonctionnent avec les commandes shell et Python. Par exemple, si dans un shell bash je tape:

aa | bb

Si je tape la commande précédente, cela veut dire que la sortie de la commande 'aa', stdout, sera l'entrée pour la commande 'bb', stdin, n'est-ce pas?

Mon problème se trouve à cette ligne de code en Python :

subprocess.call(["xsel", "-b", "-i"], stdin=tmp_file)

L'entrée pour la commande 'xsel' se trouve avec le fichier tmp_file. Cette commande fonctionne très bien. Ce que je ne comprends pas est que j'ai dû employer l'option '-i' qui est définie dans la doc de xsel de la façon suivante :

 -i, --input           Read standard input into the selection

Ma question est pourquoi dois-je employer cette option?

Par exemple, si je tape dans le shell bash :

echo xx | xsel

xsel lit son information depuis l'entrée standard qui est alimentée par la commande 'echo', n'est-ce pas? Pourquoi n'ai-je pas à employer l'option -i comme pour ma ligne de code Python? roll

Hors ligne

#2 Le 07/01/2013, à 03:33

Maisondouf

Re : Comment fonctionnent les pipes et les commandes shell avec Python

parce que le shell, c'est pas du python.
Chacun a sa syntaxe et son fonctionnement distinct.

Man xsel a écrit :

By default, this program outputs the selection without modification if both standard input and standard output are terminals (ttys).
Otherwise, the current selection is output if standard output is not a terminal (tty), and the selection is set from standard input if standard input is not a terminal (tty).

Alors effectivement depuis Python, il n'y pas de notion de pipe au sens shell, c'est le call python qui "déverse" le contenu du fichier dans l'entrée de la commande.
Comme si sous shell, on avait fait:

cat tmp_file | xsel

ASUS M5A88-v EVO avec AMD FX(tm)-8120 Eight-Core Processor,  OS principal Precise 12.04.1 LTS 63bits½
Bricoleur, menteur, inculte, inadapté social et mythomane, enfin d'après certains....
"the secret of my form is summed up in two words, no sport" (Winston Churchill)

Hors ligne

#3 Le 07/01/2013, à 04:31

Pierre Thibault

Re : Comment fonctionnent les pipes et les commandes shell avec Python

Maisondouf a écrit :

Alors effectivement depuis Python, il n'y pas de notion de pipe au sens shell, c'est le call python qui "déverse" le contenu du fichier dans l'entrée de la commande.
Comme si sous shell, on avait fait:

cat tmp_file | xsel

Je ne comprends pas. Si je fais la commande précédente dans le terminal, je n'ai pas besoin de l'option -i comme en Python. Est-ce que ça veut dire qu'il y a une erreur dans la documentation de la commande xsel?

Hors ligne

#4 Le 07/01/2013, à 09:16

pingouinux

Re : Comment fonctionnent les pipes et les commandes shell avec Python

Bonjour,
Comme l'indique l'extrait de man xsel (Maisondouf #2), l'entrée standard est traitée différemment si c'est un terminal.
Ces trois commandes vont bien lire l'entrée standard :

cat tmp_file | xsel
xsel <tmp_file
xset -i        # Lecture sur le terminal

mais pas celle-ci :

xsel

En ligne

#5 Le 07/01/2013, à 14:26

Pierre Thibault

Re : Comment fonctionnent les pipes et les commandes shell avec Python

OK. C'est ce que je vois. Donc on peut détecter si une entrée ou une sortie est un terminal. Je ne savais pas cela.

Cela ne me semble pas être en accord avec la doc qui dit:

Otherwise, the current selection is output if standard output is not a terminal (tty), and the selection is set from standard input if standard input is not a terminal (tty).

Ça dit que ça lit l'entrée standard donc je ne vois pas pourquoi je dois employer l'option -i.

Hors ligne

#6 Le 10/01/2013, à 20:43

aurelien.noce

Re : Comment fonctionnent les pipes et les commandes shell avec Python

En effet c'est bizarre ton histoire, et surtout je n'ai pas le bug chez moi... c'est quoi ta version de python/xsel ?

En même temps, l'auteur lui-même précise que son algo de defaulting est assez limite (src) et qu'il vaut mieux utiliser les options explicites comme le -i ici.

Mais bon je suis curieux de voir comprendre le pourquoi du comment. Au hasard, est-tu sûr que ton tmp_file ne vaut pas justement sys.stdin ?

Hors ligne

#7 Le 11/01/2013, à 02:04

Pierre Thibault

Re : Comment fonctionnent les pipes et les commandes shell avec Python

aurelien.noce a écrit :

En effet c'est bizarre ton histoire, et surtout je n'ai pas le bug chez moi... c'est quoi ta version de python/xsel ?

> python --version && xsel --version
Python 2.7.3
xsel version 1.2.0 by Conrad Parker <conrad@vergenet.net>
aurelien.noce a écrit :

En même temps, l'auteur lui-même précise que son algo de defaulting est assez limite (src) et qu'il vaut mieux utiliser les options explicites comme le -i ici.

OK, ça expliquerait les choses.

aurelien.noce a écrit :

Mais bon je suis curieux de voir comprendre le pourquoi du comment. Au hasard, est-tu sûr que ton tmp_file ne vaut pas justement sys.stdin ?

Non, je ne crois pas. Voici le code Python de mon petit script:

#!/usr/bin/env python

# Add for 4 spaces at each line of the current selection
# store the result in the clipboard

import subprocess
import tempfile

sel = subprocess.check_output("xsel")
end_new_line = sel.endswith("\n")
sel = sel.replace("\n", "\n    ", sel.count("\n") - int(end_new_line))
sel = "    " + sel
with tempfile.TemporaryFile(mode='w+') as tmp_file:
    tmp_file.write(sel)
    tmp_file.seek(0)
    subprocess.call(["xsel", "-b", "-i"], stdin=tmp_file)

Hors ligne

#8 Le 11/01/2013, à 11:37

aurelien.noce

Re : Comment fonctionnent les pipes et les commandes shell avec Python

ton code me donne une idée:

  - essaye laisser le mode par défaut (lecture+ecriture et binaire) sur ton tempfile
  - essaye d'appeler .flush() sur ton file descripteur histoire d'être sûr d'avoir tout est écrit avant de lancer ton process

avec ça ça devrait mieux marcher, tu confirmes ?

OK, ça expliquerait les choses.

En fait non... le code source est très clair: xsel va lire l'entrée standard ssi isatty(0) renvoie True, et après un rapide test chez moi ce n'est pas le cas dans le cas d'un appel depuis subprocess.call() avec l'option stdin settée à un fichier.
D'où l'idée qu'il n'y arrive pas parce que le fichier n'est pas prêt.

Dernière modification par aurelien.noce (Le 11/01/2013, à 11:43)

Hors ligne

#9 Le 11/01/2013, à 16:19

Pierre Thibault

Re : Comment fonctionnent les pipes et les commandes shell avec Python

Voici la nouvelle version du code:

#!/usr/bin/env python

# Add for 4 spaces at each line of the current selection
# store the result in the clipboard

import subprocess
import tempfile

sel = subprocess.check_output("xsel")
end_new_line = sel.endswith("\n")
sel = sel.replace("\n", "\n    ", sel.count("\n") - int(end_new_line))
sel = "    " + sel
with tempfile.TemporaryFile() as tmp_file:
    tmp_file.write(sel)
    tmp_file.flush()
    tmp_file.seek(0)
    subprocess.call(["xsel", "-b", "-i"], stdin=tmp_file)

Ça fonctionne toujours mais si j'enlève l'option "-i", ça ne fonctionne plus.

Hors ligne

Haut de page ↑