¿Por qué no usar `shell = True` en subprocess.Popen en Python?

Tengo un comando de shell de una línea muy largo para ser llamado por Python. Los códigos son así:

# "first way" def run_cmd ( command ): print "Run: %s" % command subprocess.call (command, shell=True) run_cmd('''sort -n -r -k5 {3} |head -n 500|awk 'OFS="\t"{{if($2-{1}>0){{print $1,$2-{1},$3+{1},$4,$5}}}}' > {2}'''.format(top_count,extend/2,mid,summit)) 

Estos códigos funcionan, pero siempre se queja así:

 sort: write failed: standard output: Broken pipe sort: write error awk: (FILENAME=- FNR=132) fatal: print to "standard output" failed (Broken pipe) 

De acuerdo con una respuesta anterior , necesito usar un script más largo para terminar esto, como:

 # "second way" p1 = Popen("sort -n -r -k5 %s"%summit, stdout=PIPE) p2 = Popen("head -n 500", stdin=p1.stdout, stdout=PIPE) # and so on .......... 

Mis preguntas son:

(1) si la “segunda vía” será más lenta que la “primera vía”

    (2) de todos modos, si tengo que escribir de “primera manera” (porque es más rápido de escribir), ¿cómo puedo evitar la queja como broken pipe

    (3) ¿Cuál podría ser la razón más convincente por la que no debería escribir en “primera forma”?

    Usar shell = True puede ser un riesgo para la seguridad si sus datos de entrada provienen de una fuente no confiable. Por ejemplo, si el contenido de su variable mid es "/dev/null; rm -rf /" . Este no parece ser el caso en su situación, por lo que no me preocuparía demasiado.

    En su código, escriba el resultado de awk directamente en el nombre del archivo a mid . Para depurar el problema, es posible que desee utilizar subprocess.check_output y leer el resultado de su invocación awk en su progtwig python.

     cmd = """sort -n -r -k5 %s | head -n 500| awk 'OFS="\t"{{if($2-{1}>0){{print $1,$2-{1},$3+{1},$4,$5}}}}'""".format(summit, top_count) subprocess.check_call(cmd, shell=True, stdout=file) 

    (1) si la “segunda vía” será más lenta que la “primera vía”

    Iniciar un nuevo proceso es una operación costosa, por lo tanto, no debería haber una gran diferencia entre permitir que el shell analice la línea de comandos e inicie procesos secundarios y hacerlo usted mismo en Python. El único punto de referencia que importa es su código en su hardware. Mídelo.

    (2) de todos modos, si tengo que escribir de “primera manera” (porque es más rápido de escribir), ¿cómo puedo evitar la queja como una tubería rota?

    La primera “tubería rota” podría ser similar a: ‘sí’ reportando un error con subprocess se comunicará () . Intente la solución que he proporcionado allí .

    La segunda tubería rota que podría arreglar redirigiendo la salida estándar de la tubería al archivo mid :

     with open(mid, 'wb') as file: check_call(pipeline, shell=True, stdout=file) 

    Implementa > {2} en tu comando sin el shell.

    (3) ¿Cuál podría ser la razón más convincente por la que no debería escribir en “primera forma”?

    Si alguno de top_count , extend , mid , summit proviene de una fuente que no está completamente bajo su control, corre el riesgo de ejecutar un comando arbitrario bajo su usuario.


    plumbum módulo plumbum proporciona seguridad y legibilidad (mida el rendimiento del tiempo si es importante para usted en este caso):

     from plumbum.cmd import awk, head, sort awk_cmd = 'OFS="\t"{if($2-%s>0){print $1,$2-%s,$3+%s,$4,$5}}' % (extend/2,)*3 (sort["-n", "-r", "-k5", summit] | head["-n", "500"] | awk[awk_cmd] > mid)() 

    Vea, ¿Cómo uso subprocess.Popen para conectar varios procesos por canalizaciones?

    Es poco probable que sea más lento, pero siempre puede probarlo con tiempo, para estar seguro. Hay dos buenas razones para no hacerlo de la primera manera. La primera es que si bien puede ser un poco más rápido escribir la primera vez, la legibilidad se reduce considerablemente y la legibilidad cuenta . El segundo es que el uso de shell=True es un gran riesgo para la seguridad , y debe evitarse como una cuestión de principal.