2011-02-11 13 views
64

Quello che faccio nella riga di comando:Python: come reindirizzare l'output con sottoprocesso?

cat file1 file2 file3 > myfile 

Quello che voglio fare con python:

import subprocess, shlex 
my_cmd = 'cat file1 file2 file3 > myfile' 
args = shlex.split(my_cmd) 
subprocess.call(args) # spits the output in the window i call my python program 
+0

L'esecuzione di un comando di questo tipo in sottoprocesso non fornisce alcun risultato. Potresti volerlo eseguire senza _> myfile_ reindirizzando l'output da _cat file1 file2 file3_ in python? – PoltoS

+0

@PoltoS Desidero unire alcuni file e quindi elaborare il file risultante. Pensavo che usare il gatto fosse l'alternativa più semplice. C'è un modo migliore/pitonioso per farlo? – catatemypythoncode

+0

La soluzione 'os.sendfile()' -based è possibile, vedere [Riprodurre il comando unix cat in python] (http://stackoverflow.com/q/11532980/4279) – jfs

risposta

23

UPDATE: os.system è scoraggiato, anche se ancora disponibile in Python 3.


Uso os.system:

os.system(my_cmd) 

Se davvero si vuole utilizzare sottoprocesso, ecco la soluzione (per lo più sollevata dalla documentazione per sottoprocesso):

p = subprocess.Popen(my_cmd, shell=True) 
os.waitpid(p.pid, 0) 

OTOH, è possibile evitare le chiamate di sistema del tutto:

import shutil 

with open('myfile', 'w') as outfile: 
    for infile in ('file1', 'file2', 'file3'): 
     shutil.copyfileobj(open(infile), outfile) 
+1

Funziona, ma lascia che ti chieda allora: qual è il punto della libreria di sottoprocesso se os.system ha già finito il lavoro? Ho la sensazione che avrei dovuto usare il subprocesso perché è una libreria dedicata a questo compito, anche se, dato che lo sto facendo solo per me, stavolta starò bene con os.system. – catatemypythoncode

+0

La libreria di sottoprocesso è molto più flessibile di 'os.system' e può modellare' os.system' con precisione, ma è anche più complesso con cui lavorare. –

+11

'os.system' precede' sottoprocesso'. Il primo è un'API legacy che quest'ultimo intende sostituire. – Santa

4

@ PoltoS Voglio unire alcuni file e quindi elaborare il file risultante. Pensavo che usare il gatto fosse l'alternativa più semplice. C'è un modo migliore/pitonioso per farlo?

Naturalmente:

with open('myfile', 'w') as outfile: 
    for infilename in ['file1', 'file2', 'file3']: 
     with open(infilename) as infile: 
      outfile.write(infile.read()) 
165

Per rispondere alla tua domanda iniziale, per reindirizzare l'uscita, basta passare un handle di file aperto per la stdout argomento per subprocess.call:

# Use a list of args instead of a string 
input_files = ['file1', 'file2', 'file3'] 
my_cmd = ['cat'] + input_files 
with open('myfile', "w") as outfile: 
    subprocess.call(my_cmd, stdout=outfile) 

ma come altri hanno sottolineato, l'uso di un comando esterno come cat per questo scopo è completamente estraneo.

+2

Questa dovrebbe essere la risposta alla domanda generale di piping quando si utilizza la shell da Python –

+25

Questa è la risposta corretta, non quella contrassegnata come corretta. –

+0

Questa è la risposta corretta, l'approccio migliore. –

0

Un caso interessante sarebbe quello di aggiornare un file aggiungendo file simile ad esso. Quindi non si dovrebbe creare un nuovo file nel processo. È particolarmente utile nel caso in cui sia necessario aggiungere un file di grandi dimensioni. Ecco una possibilità utilizzando la linea di comando di teminal direttamente da Python.

import subprocess32 as sub 

with open("A.csv","a") as f: 
    f.flush() 
    sub.Popen(["cat","temp.csv"],stdout=f) 
0
size = 'ffprobe -v error -show_entries format=size -of default=noprint_wrappers=1:nokey=1 dump.mp4 > file' 
proc = subprocess.Popen(shlex.split(size), shell=True) 
time.sleep(1) 
proc.terminate() #proc.kill() modify it by a suggestion 
size = "" 
with open('file', 'r') as infile: 
    for line in infile.readlines(): 
     size += line.strip() 

print(size) 
os.remove('file') 

Quando si utilizza sottoprocesso, il processo deve essere killed.This è un example.If non uccidere il processo, file di sarà vuoto e si può leggere nothing.It può funzionare su Windows. Non posso assicurarmi che possa funzionare su Unix.

+0

È un esempio di codice errato (non funzionerà su Unix, mostra delle cattive pratiche per line in .readlines(): ',' ​​s + = ') e' proc.kill() 'può portare alla perdita di informazioni in generale (non consente al sottoprocesso di terminare con grazia (su Unix) - il contenuto non sparso viene perso). Ad ogni modo, la nota sul buffering è più appropriata come commento. – jfs

+0

Lo eseguo su Windows è OK (perché kill è uguale a terminare su Windows). Su Unix potrebbe essere necessario utilizzare proc.terminate(). @ J.F. Sebastian Non ho Unix System sul mio computer. – wyx

+0

Se sei su Windows, rilascia 'shlex.split()', rilascia 'shell = True', rilascia'> file', rilascia 'open()', etc e usa 'stdout = PIPE',' Timer (1, proc.terminate) .start() '; 'output = proc.communicate() [0]' invece. Ecco [esempio completo] (http://stackoverflow.com/a/27995163/4279). Altre soluzioni: [Interrompe la lettura dell'output del processo in Python senza bloccarsi?] (Http://stackoverflow.com/q/4417962/4279) Nota: non è richiesto nella domanda che sia necessario interrompere manualmente il processo figlio - si potrebbe affrontare altri problemi, ad esempio, un processo potrebbe comportarsi in modo diverso se il suo stdout è un tty ma è off-topic. – jfs

Problemi correlati