Tengo un script en el que estoy tratando de usar subprocess.call para ejecutar una serie de comandos de shell, pero parece que algunos comandos se omiten cuando se ejecutan.

Específicamente:

#!/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 )

Y genera esto como salida:

Python d3.py

Sedcmd = ['sort', /var/folders/3h/_0xwt5bx0hx8tgx06cmq9h_4f183ql/T/tmp5Gp0ff.xx ',' | ',' uniq ',' | ',' sed ',' -e ',' "s / bigstring de palabra / menor / "',' | ',' columna ',' -t ',' -s ','" => "'] /var/folders/3h/_0xwt5bx0hx8tgx06cmq9h_4f183ql/T/tmp5Gp0ff.xx sort: open failed: |: No existe tal archivo o directorio
ordenar: opción inválida - e Intente "sort --help" para obtener más información.

El primer 'sort: open failed: |: No existe tal archivo ... es de la primera llamada de subproceso [' sort ',' | ',' uniq '], stdin = grepfd) La opción' sort: invalid - e. .es de la segunda llamada al subproceso (sedcmd).

He visto muchos ejemplos que usan tuberías en este contexto, entonces, ¿qué estoy haciendo mal?
¡Gracias!

2
NotCharlie 8 sep. 2017 a las 16:32

2 respuestas

La mejor respuesta

Esta es una clase que ejecutará un comando con un número arbitrario de tuberías:

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

Este ejemplo muestra cómo usar la clase:

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

Creé este archivo de muestra para probar:

sample.txt

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

Salida

a       smaller   b
blah1  blah2      blah3
list1  list2      list3
word1  word2      word3
2
David Cullen 8 sep. 2017 a las 18:48

Entonces, si en un comando desea usar tuberías de shell, puede agregar shell = True en el subproceso: por lo que será así:

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)

Pero tenga cuidado con shell = True , se desaconseja encarecidamente utilizarlo: documentación oficial del subproceso

Entonces, si desea usar tuberías sin shell = True, puede usar subprocees.PIPE en la salida estándar, y aquí hay un ejemplo de cómo hacerlo: respuesta de stackoveflow

0
slim tabka 8 sep. 2017 a las 14:08