Le altre risposte qui spiegano adeguatamente le avvertenze di sicurezza che sono anche menzionate nella subprocess
documentazione. Ma oltre a ciò, l'overhead di avviare una shell per avviare il programma che si desidera eseguire è spesso inutile e decisamente sciocco per le situazioni in cui non si utilizza effettivamente nessuna delle funzionalità della shell. Inoltre, l'ulteriore complessità nascosta dovrebbe spaventarti, soprattutto se non hai molta familiarità con la shell o i servizi che fornisce.
Laddove le interazioni con la shell non sono banali, ora è necessario che il lettore e il manutentore dello script Python (che può essere o meno il tuo sé futuro) per comprendere sia lo script Python sia lo script shell. Ricorda il motto di Python "esplicito è meglio che implicito";anche quando il codice Python sarà in qualche modo più complesso dello script di shell equivalente (e spesso molto conciso), potresti essere meglio rimuovere la shell e sostituire la funzionalità con costrutti Python nativi. Ridurre al minimo il lavoro svolto in un processo esterno e mantenere il controllo all'interno del proprio codice per quanto possibile è spesso una buona idea semplicemente perché migliora la visibilità e riduce i rischi di effetti collaterali - desiderati o indesiderati.
Espansione jolly, interpolazione variabile e reindirizzamento sono tutti semplici da sostituire con costrutti Python nativi. Una complessa pipeline di shell in cui parti o tutte non possono essere ragionevolmente riscritte in Python sarebbe l'unica situazione in cui forse potresti prendere in considerazione l'uso della shell. Dovresti comunque assicurarti di comprendere le prestazioni e le implicazioni sulla sicurezza.
Nel caso banale, per evitare shell=True
, è sufficiente sostituire
subprocess.Popen("command -with -options 'like this' and\\ an\\ argument", shell=True)
con
subprocess.Popen(['command', '-with','-options', 'like this', 'and an argument'])
Si noti come il primo argomento sia un elenco di stringhe a cui passare execvp()
e come non sia necessario (o utile o corretto) quotare stringhe e metacaratteri di shell con escape di backslash. Forse vedi anche Quando racchiudere le virgolette attorno a una variabile shell?
Per inciso, molto spesso vuoi evitare Popen
se uno dei wrapper più semplici nel subprocess
pacchetto fa quello che vuoi. Se hai un Python abbastanza recente, probabilmente dovresti usarlo subprocess.run
.
- Con
check=True
esso fallirà se il comando che hai eseguito non è riuscito.
- Con
stdout=subprocess.PIPE
esso acquisirà l'output del comando.
- Un po 'oscuramente, con
universal_newlines=True
esso decodificherà l'output in una stringa Unicode corretta (è solo bytes
nella codifica del sistema altrimenti, su Python 3).
In caso contrario, per molte attività, si desidera check_output
ottenere l'output da un comando, verificando che abbia avuto esito positivo o check_call
se non è presente alcun output da raccogliere.
Chiuderò con una citazione di David Korn: "È più facile scrivere una shell portatile che uno script di shell portatile". Anche subprocess.run('echo "$HOME"', shell=True)
non è portabile su Windows.
-l
viene passato a/bin/sh
(la shell) invece dells
programma su Unix seshell=True
.shell=True
Nella maggior parte dei casi l' argomento stringa deve essere utilizzato anziché un elenco.