stdout Redirect de python pour les appels C
-
26-10-2019 - |
Question
Il est question de suivi de concernant spécifiquement son réponse.
D'un module python Je fais appel Bonjour tout le monde exécutable qui affiche simplement Hello World
STDOUT. Je suis intéressé à rediriger cette sortie vers un StringIO
python et a couru dans cette réponse qui me amène presque tout le chemin à la solution .
La partie critique de cette réponse est ce segment de code:
1. def redirect_stdout():
2. print "Redirecting stdout"
3. sys.stdout.flush() # <--- important when redirecting to files
4. newstdout = os.dup(1)
5. devnull = os.open('/dev/null', os.O_WRONLY)
6. os.dup2(devnull, 1)
7. os.close(devnull)
8. sys.stdout = os.fdopen(newstdout, 'w')
Je voudrais également restaurer le stdout comme avant la redirection.
Questions
- Qu'est-ce qui se passe exactement dans la fonction ci-dessus?
- Que fait
dup
etdup2
? - Qu'est-ce que
/dev/null
? - Qu'est-ce que la ligne 8 fait? (
sys.stdout = os.fdopen(newstdout, 'w')
)
- Que fait
- Comment puis-je stocker le stdout dans un objet
StringIO
? - Comment puis-je restaurer le stdout après l'appel à mon Bonjour tout le monde programme?
Je suis assez sûr qu'une fois que j'ai la réponse à ma question 1 que les réponses des questions 2 et 3 seront faciles. J'ai décidé de les poster toute façon peut-être pousser la réponse de la question 1 dans le sens où je veux aller.
La solution
J'ai écrit ci-dessous quelques commentaires supplémentaires qui devraient rendre plus clairement ce qu'il se passe à l'intérieur de la fonction redirect_stdout
:
def redirect_stdout():
print "Redirecting stdout"
sys.stdout.flush() # <--- important when redirecting to files
# Duplicate stdout (file descriptor 1)
# to a different file descriptor number
newstdout = os.dup(1)
# /dev/null is used just to discard what is being printed
devnull = os.open('/dev/null', os.O_WRONLY)
# Duplicate the file descriptor for /dev/null
# and overwrite the value for stdout (file descriptor 1)
os.dup2(devnull, 1)
# Close devnull after duplication (no longer needed)
os.close(devnull)
# Use the original stdout to still be able
# to print to stdout within python
sys.stdout = os.fdopen(newstdout, 'w')
Une chose importante à noter est qu'un processus obtient trois descripteurs de fichiers rel="noreferrer"> à partir du système d'exploitation lorsque lancé:
- stdin: 0
- stdout: 1
- stderr: 2
Comme expliqué dans les commentaires, le code ci-dessus prend avantage du descripteur de fichier pour stdout et les fonctions de duplication de descripteur de fichier pour faire duper le code C en utilisant un stdout différent, tout en conservant une référence à la sortie standard d'origine dans le code python pour être en mesure d'imprimer.
Autres conseils
/dev/null
est un fichier spécial (tout sous UNIX est un fichier!) Qui avale tout écrit à lui comme un trou noir. dup
dupliquer un descripteur de fichier. Si vous utilisez Windows, un descripteur de fichier sous UNIX est un entier spécial qui représente un fichier ouvert, il est comme une poignée de fichiers Windows.
Le programme ouvre /dev/null
pour l'écriture (seulement), en prenant une copie du descripteur de fichier, fermer le fichier ouvert (car ayant un descripteur de fichier est suffisant pour UNIX pour écrire dans un fichier, vous n'avez pas besoin de garder la ressources ouvertes), en assignant le fichier ouvert à sys.stdout
.
Souvenez-vous sys
est le module Python qui représente toutes sortes de ressources spécifiques au système, comme le système de fichiers. Ainsi, sous UNIX sys.stdout
représentera /dev/stdout
à savoir le flux de STDOUT
du système.
Alors, tout à fait, ce code est duper Python en pensant que /dev/null/
est STDOUT
maintenant chaque fois que votre écriture de programme à STDOUT
avec, par exemple, la déclaration de print
(fonction python3), alors il sera vraiment écrit à /dev/null
et vous ne jamais voir le texte résultant sur votre console.
pages de manuel pour les fonctions d'exécution C qui sous-tendent ces fonctions Python.
En fait, ils dupliquent un descripteur de fichier, soit dans un nouveau descripteur de fichier (avec dup()
) ou dans un descripteur de fichier spécifié dans l'appel, avec dup2()
.