2017-04-14 4 views
0

J'essaie de lire un fichier gtf puis de le modifier (en utilisant subprocess, grep et awk) avant de le charger dans les pandas.Comment sous-traiter directement les fichiers sur la console (avec ou sans StringIO)?

J'ai un nom de fichier qui a des informations d'en-tête (indiqué par #), donc j'ai besoin de grep cela et le supprimer d'abord. Je peux le faire en python mais je veux introduire grep dans mon pipeline pour rendre le traitement plus efficace.

J'ai essayé de faire:

import subprocess 
from io import StringIO 

gtf_file = open('chr2_only.gtf', 'r').read() 
gtf_update = subprocess.Popen(["grep '^#' " + StringIO(gtf_file)], shell=True) 

et

gtf_update = subprocess.Popen(["grep '^#' " + gtf_file], shell=True) 

Ces deux codes renvoient une erreur, pour la 1ère tentative était:

Traceback (most recent call last): 
    File "/home/everestial007/PycharmProjects/stitcher/pHASE-Stitcher-Markov/markov_final_test/phase_to_vcf.py", line 39, in <module> gtf_update = subprocess.Popen(["grep '^#' " + StringIO(gtf_file)], shell=True) 
TypeError: Can't convert '_io.StringIO' object to str implicitly 

Cependant , si je précise le filen amme directement cela fonctionne:

gtf_update = subprocess.Popen(["grep '^#' chr2_only.gtf"], shell=True) 

et la sortie est:

<subprocess.Popen object at 0x7fc12e5ea588> 
#!genome-build v.1.0 
#!genome-version JGI8X 
#!genome-date 2008-12 
#!genome-build-accession GCA_000004255.1 
#!genebuild-last-updated 2008-12 

Quelqu'un pourrait-il s'il vous plaît fournir différents exemples pour le problème comme celui-ci, et expliquer aussi pourquoi je reçois l'erreur et pourquoi/comment serait possible d'exécuter sous-processus directement sur les fichiers chargés sur la console/mémoire?

J'ai aussi essayé d'utiliser subprocess avec call, check_call, check_output, etc., mais j'ai eu plusieurs messages d'erreur différents, comme ceux-ci:

OSError: [Errno 7] Argument list too long 

et

Subprocess in Python: File Name too long 
+0

J'ai vu "Sous-processus en Python: Nom de fichier trop long" avant. Cela m'est arrivé lorsque je passais involontairement le texte dans un fichier ouvert en tant qu'argument à Popen au lieu d'une chaîne pour le chemin du nom de fichier. Lorsque vous affectez 'gtf_update = subprocess.Popen ([" grep '^ #' chr2_only.gtf "], shell = True)', vous pouvez alors sortir cette commande en utilisant 'gtf_update.communicate()' – JacobIRR

+0

Dans votre commande 'grep', vous devez passer le * nom * du fichier, comme vous le faites dans votre exemple de travail. les premiers, vous essayez d'ajouter un objet StringIO ou un objet de fichier à la chaîne '' grep '^ #' "', et Python ne peut pas les convertir en une chaîne.Ajoutez simplement le nom de fichier à la place –

+0

Je ne veux pas lire le nom du fichier sur le sous-processus, la raison étant que je dois utiliser ce fichier pour différentes branches du pipeline, donc je veux le lire de façon pythonique 'data = open (....) .read() ', puis utilisez cette 'data' pour faire des choses différentes.Essayez simplement d'économiser de la mémoire et du temps en ne lisant pas les mêmes fichiers encore et encore – everestial007

Répondre

2

Voici une solution qui vous permet envoie une chaîne à grep. Essentiellement, vous déclarez dans le constructeur Popen que vous voulez communiquer avec le programme appelé via stdin et stdout. Vous envoyez ensuite l'entrée via la communication et recevez la sortie en tant que valeur de retour de communiquer.

#!/usr/bin/python 

import subprocess 

gtf_file = open('chr2_only.gtf', 'r').read() 
gtf_update = subprocess.Popen(["grep '^#' "], shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) 

# stdout, stderr (but latter is empty) 
gtf_filtered, _ = gtf_update.communicate(gtf_file) 

print gtf_filtered 

Notez qu'il est sage de ne pas utiliser shell=True. Par conséquent, la ligne Popen doit être écrit

gtf_update = subprocess.Popen(["grep", '^#'], shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE) 

La raison est que vous n'avez pas besoin du shell pour analyser les arguments à un seul exécutable. Donc, vous évitez les frais généraux inutiles. Il est également préférable du point de vue de la sécurité, du moins si un argument est potentiellement dangereux car il provient d'un utilisateur (pensez à un nom de fichier contenant |). Notez que du point de vue des performances, je pense que la lecture directe du fichier avec grep est plus rapide que la première lecture du fichier avec python, puis son envoi à grep.