En bash, me doy cuenta de que si falla un comando que usa la redirección, los programas que se ejecutan antes no se ejecutan.
Por ejemplo, este programa abre el archivo "a" y escribe 50 bytes en el archivo "a". Sin embargo, ejecutar este comando con redirección a un archivo con permisos insuficientes (~ root / log), no produce cambios en el tamaño del archivo de "a".
$ ./write_file.py >> ~root/log
-bash: /var/root/log: Permission denied
cdal at Mac in ~/experimental/unix_write
$ ls -lt
total 16
-rw-rw-r-- 1 cdal staff 0 Apr 27 08:54 a <-- SHOULD BE 50 BYTES
Uno podría pensar que el programa se ejecutaría, capturaría cualquier salida (pero también escribiría en el archivo "a") y luego no podría escribir ninguna salida en ~ root / log. En cambio, el programa nunca se ejecuta.
¿Por qué es esto y cómo elige bash el orden de los "controles" que realiza antes de ejecutar un programa? ¿Se realizan también otras verificaciones?
ps Estoy tratando de determinar si un programa ejecutado bajo cron se ejecutó realmente cuando se lo redirigió a un archivo de "permiso denegado".
fuente
stdout
para hacer exactamente eso. Por lo tanto, no verá ningún resultado, aunque su programa se haya ejecutado.write_file.py
programa y envíe su salida a~root/log
bash:" Lo siento, ¡pero no tiene permiso para escribir en ese archivo! "El shell está haciendo exactamente lo que debe hacer. Si no puede hacer lo que le pidió hazlo, te informa inmediatamente por qué hay un problema, dándote la oportunidad de decidir cómo lidiar con él. Para todos los mantenedores de bash saben, podrían ocurrir cosas muy malas si ejecutas ese comando y no puedes guardar la salida. Si fuera lo suficientemente importante como para designar un lugar para guardarlo, sería un error que ASS | U | ME estuviese bien correr sin guardar stdout.Respuestas:
En realidad no se trata de ordenar cheques, simplemente el orden en que el shell configura las cosas. Las redirecciones se configuran antes de ejecutar el comando; así que en su ejemplo, el shell intenta abrirse
~root/log
para agregar antes de intentar hacer algo que involucre./write_file.py
. Como el archivo de registro no se puede abrir, la redirección falla y el shell deja de procesar la línea de comando en ese punto.Una forma de demostrar esto es tomar un archivo no ejecutable e intentar ejecutarlo:
Esto muestra que el shell ni siquiera mira
./demo
cuando no se puede configurar la redirección.fuente
Desde la página de manual de bash, sección REDIRECCIÓN (énfasis por mí):
Por lo tanto, el shell intenta abrir el archivo de destino
stdout
, que falla, y el comando no se ejecuta en absoluto.fuente
Vale la pena observar que el shell debe establecer redirecciones antes de iniciar el programa.
Considera tu ejemplo:
Lo que sucede en el shell es:
fork()
; el proceso hijo hereda los descriptores de archivo abierto de su padre (el shell).fopen()
(la expansión de) "~ root / log", ydup2()
lo fd 1 (yclose()
el fd temporal). Sifopen()
falla, llameexit()
para informar el error al padre.exec()
"./write_file.py". Este proceso ya no ejecuta ninguno de nuestros códigos (a menos que no podamos ejecutarlo, en cuyo caso debemosexit()
informar el error al padre).wait()
que el hijo termine y maneje su código de salida (copiándolo$?
, al menos).Por lo tanto, la redirección debe ocurrir en el elemento secundario entre
fork()
yexec()
: no puede suceder antesfork()
porque no debe cambiar la salida estándar del shell, y no puede suceder despuésexec()
porque el nombre de archivo y el código ejecutable del shell ahora han sido reemplazados por el programa Python . El padre no tiene acceso a los descriptores de archivo del niño (e incluso si lo hiciera, no podría garantizar la redirección entreexec()
y la primera escritura en stdout).fuente
Lamento informarle que es todo lo contrario. El shell necesita abrir su E / S primero y luego pasa el control al programa.
tee
podría ser útil en este caso:./write_file.py | tee -a ~root/log > /dev/null
fuente