2017-09-08 1 views
1

J'ai un script dans lequel j'essaie d'utiliser subprocess.call pour exécuter une série de commandes shell, mais qui semble avoir certaines commandes omises lors de l'exécution.python subprocess.call et pipes

Plus précisément:

#!/usr/bin/python 
import tempfile 
import subprocess 
import os 
import re 


grepfd, grepfpath = tempfile.mkstemp(suffix=".xx") 
sedfd, sedfpath = tempfile.mkstemp(suffix=".xx") 

# grepoutfile = open(grepfpath, 'w') 
sedoutfile = open(sedfpath, 'w') 

subprocess.call(['cp','/Users/bobby/Downloads/sample.txt', grepfpath]) 

sedcmd = [ 'sort', 
      grepfpath, 
      '|', 
      'uniq', 
      '|', 
      'sed', 
      '-e', 
      '"s/bigstring of word/ smaller /"', 
      '|', 
      'column', 
      '-t', 
      '-s', 
      '"=>"' ] 

print "sedcmd = ", sedcmd 
subprocess.call(['ls', grepfpath ]) 
subprocess.call(['sort', '|', 'uniq' ], stdin = grepfd) 
subprocess.call(sedcmd, stdout = sedoutfile) 

Et il génère cette sortie comme:

python d3.py

sedcmd = [ 'type',/var/dossiers/3h/_0xwt5bx0hx8tgx06cmq9h_4f183ql/T/tmp5Gp0ff.xx ',' | ',' uniq ',' | ',' sed ',' -e ',' "s/bigstring de mot/plus petit /" ',' | ',' colonne ',' -t ',' -s ',' "=>" ' /var/folders/3h/_0xwt5bx0hx8tgx06cmq9h_4f183ql/T/tmp5Gp0ff.xx tri: ouvert échoué: |: aucun fichier ou répertoire
tri: option invalide - e Essayez `sort --help 'pour plus d'informations. Le premier 'tri: open a échoué: |: Aucun fichier de ce type ... ne provient du premier sous-processus [' sort ',' | ',' uniq '], stdin = grepfd) La' tri: invalide option - e .. provient du second appel de sous-processus (sedcmd).

J'ai vu beaucoup d'exemples qui utilisent des tuyaux dans ce contexte - alors qu'est-ce que je fais mal?
Merci!

+0

Si vous essayez d'utiliser les fonctionnalités shell comme les tuyaux, vous allez besoin de passer une chaîne (pas une liste) et de définir 'shell = True'. Lisez la documentation 'subprocess' pour plus de détails. – larsks

Répondre

1

C'est une classe qui va exécuter une commande avec un nombre arbitraire de tuyaux:

pipeline.py

import shlex 
import subprocess 

class Pipeline(object): 
    def __init__(self, command): 
     self.command = command 
     self.command_list = self.command.split('|') 
     self.output = None 
     self.errors = None 
     self.status = None 
     self.result = None 

    def run(self): 
     process_list = list() 
     previous_process = None 
     for command in self.command_list: 
      args = shlex.split(command) 
      if previous_process is None: 
       process = subprocess.Popen(args, stdout=subprocess.PIPE) 
      else: 
       process = subprocess.Popen(args, 
              stdin=previous_process.stdout, 
              stdout=subprocess.PIPE) 
      process_list.append(process) 
      previous_process = process 
     last_process = process_list[-1] 
     self.output, self.errors = last_process.communicate() 
     self.status = last_process.returncode 
     self.result = (0 == self.status) 
     return self.result 

Cet exemple montre comment utiliser la classe:

harness.py

from pipeline import Pipeline 

if __name__ == '__main__': 
    command = '|'.join([ 
     "sort %s", 
     "uniq", 
     "sed -e 's/bigstring of word/ smaller /'", 
     "column -t -s '=>'" 
    ]) 
    command = command % 'sample.txt' 
    pipeline = Pipeline(command) 
    if not pipeline.run(): 
     print "ERROR: Pipeline failed" 
    else: 
     print pipeline.output 

J'ai créé ce fichier échantillon pour le test:

sample.txt

word1>word2=word3 
list1>list2=list3 
a>bigstring of word=b 
blah1>blah2=blah3 

Sortie

a  smaller b 
blah1 blah2  blah3 
list1 list2  list3 
word1 word2  word3 
0

Donc, si dans une commande que vous souhaitez utiliser des tuyaux shell que vous pouvez ajouter shell = True dans le sous-processus: donc ce sera comme ceci:

sedcmd = 'sort /var/folders/3h/_0xwt5bx0hx8tgx06cmq9h_4f183ql/T/tmp5Gp0ff.xx | uniq | sed -e "s/bigstring of word/ smaller /" | column -t -s "=>" ' 
subprocess.call(sedcmd, shell=True) 

Mais attention avec shell = True, il est fortement déconseillé de l'utiliser: subprocess official documentation

donc, si vous voulez utiliser des tuyaux sans shell = True vous pouvez utiliser subprocees.PIPE dans le stdout, et voici un exemple sur la façon de le faire: stackoveflow answer