Cuando redirijo la salida de un comando a un archivo (por ejemplo, echo Hello > file
) ¿se garantizará que ese archivo tenga dichos datos justo después de que el comando salga? ¿O todavía hay una ventana muy pequeña entre las salidas de comando y los datos escritos en el archivo? Me gustaría leer el archivo justo después de que salga el comando, pero no quiero leer un archivo vacío.
linux
hard-drive
process
file-io
Eric
fuente
fuente
echo
y>
no procesos separados (de corta duración)? ¿Y dónde se ejecuta la salida deecho
permanecer antes>
?>
es redirección de shell. Es lo mismo que si el programa hubiera abierto el archivo nombrado para escribir y reemplazado stdout con él, que es exactamente lo que hace el shell.file
contenidoHello
independientemente de si está enjuagado o no.Respuestas:
Hay múltiples capas de memorias intermedias / cachés involucradas.
El caché de la CPU.
Los datos se juntan byte a byte y se almacenan en el caché de la CPU. Si el caché de la CPU está lleno y no se ha accedido a los datos durante un tiempo, el bloque que contiene nuestros datos puede escribirse en la memoria principal. Estos están, en su mayor parte, ocultos para los programadores de aplicaciones.
Los amortiguadores en proceso.
Hay un poco de memoria reservada en el proceso donde se recopilan los datos, por lo que debemos realizar la menor cantidad posible de solicitudes al sistema operativo, ya que es relativamente costoso. El proceso copia los datos en estos búferes, que nuevamente pueden estar respaldados por cachés de la CPU, por lo que no hay garantía de que los datos se copien en la memoria principal. La aplicación necesita vaciar explícitamente estos búferes, por ejemplo, usando fclose (3) o fsync (3). La función exit (3) también hace esto antes de que finalice el proceso, mientras que la función _exit (2) no lo hace , por lo que hay una gran advertencia en la página del manual para que esa función lo llame solo si sabe lo que es haciendo.
El kernel amortigua
Luego, el sistema operativo mantiene su propia caché, para minimizar la cantidad de solicitudes que necesita enviar a los discos. Este caché no pertenece a ningún proceso en particular, por lo que los datos allí pueden pertenecer a procesos que ya han finalizado, y dado que todos los accesos pasan por aquí, el siguiente programa verá los datos si ha llegado aquí. El núcleo escribirá estos datos en los discos cuando tenga tiempo de hacerlo o cuando se le solicite explícitamente.
El caché de la unidad
Las unidades de disco también mantienen un caché para acelerar los accesos. Estos se escriben con bastante rapidez, y hay un comando para escribir los datos restantes en los cachés e informar cuando se completa, que el sistema operativo utiliza en el apagado para asegurarse de que no quedan datos sin escribir antes de apagarse.
Para su aplicación, es suficiente que los datos se registren en las memorias intermedias del kernel (los datos reales todavía pueden vivir en cachés de CPU en este momento, y podrían no haberse escrito en la memoria principal): el proceso "echo" finaliza, lo que significa que cualquier búfer en proceso debe haberse vaciado y los datos entregados al sistema operativo, y cuando inicia un nuevo proceso, se garantiza que el sistema operativo devolverá los mismos datos cuando se le solicite.
fuente
Si la aplicación no tiene cachés internos, los cambios se escribirán inmediatamente en el archivo. Lo mismo para tu ejemplo. El archivo es una entidad lógica en la memoria que se actualizará inmediatamente. Cualquier operación posterior en el archivo verá los cambios realizados por el programa.
Sin embargo , esto no significa que el cambio se haya escrito en el disco físico. Los cambios pueden permanecer en las cachés del sistema de archivos del sistema operativo o en las cachés de hardware. Para vaciar los búferes del sistema de archivos, use el
sync
comandoNo deberías encontrarte con ningún problema práctico aquí.
fuente
exit
no se llama al menos implícitamente). Otras bibliotecas / lenguajes (por ejemplo, Java!) Ofrecen menos garantías.En general la respuesta es no .
Depende del comando. Como mencionan las otras respuestas, si el comando no almacena internamente los datos, todos los datos estarán disponibles cuando finalice el comando.
Pero la mayoría, si no todas, las bibliotecas de E / S estándar hacen stdout de búfer de forma predeterminada (hasta cierto punto) y ofrecen diferentes garantías sobre el vaciado automático de búferes cuando se cierra la aplicación.
C garantiza que una salida normal vaciará los tampones . "Salida normal" significa que
exit
se llama, ya sea explícitamente o al regresar demain
. Sin embargo, una salida anormal puede eludir esta llamada (y, por lo tanto, dejar atrás los búferes sin vaciar).Aquí hay un ejemplo simple:
Si compila esto y lo ejecuta,
test
será no necesariamente deben escribir en la salida estándar.Otros lenguajes de programación ofrecen aún menos garantías: Java, por ejemplo, no se auto-descarga al finalizar el programa . Si el búfer de salida contiene una línea sin terminar, puede perderse, a menos que
System.out.flush()
se llame explícitamente.Dicho esto, su cuerpo pregunta se refiere a algo ligeramente diferente: si los datos llegan en el archivo en absoluto , debe hacerlo inmediatamente después de la expiración de la orden (sujeta a las advertencias descritas en las otras respuestas).
fuente
write()
opwrite()
llamada al sistema ocurrirá antes de salir del proceso, y fue entonces cuando los cambios en los archivos se hacen visibles. Entonces, el último cambio de archivo es definitivamente antes de la finalización del proceso, inmediatamente antes, a más tardar. Creo que incluso con unmmap(MAP_SHARED)
archivo, no hay forma de que algo observe la finalización del proceso antes de que ocurran todos los cambios de archivo.Creo que ninguna pregunta aborda este problema lo suficiente todavía:
Como explican las otras respuestas, un programa que se comporta bien vacía sus búferes de archivos internos antes de que el proceso finalice normalmente . Posteriormente, los datos pueden permanecer en el núcleo o en las memorias intermedias de hardware antes de escribirse en el almacenamiento persistente. Sin embargo , la semántica del sistema de archivos de Linux garantiza que todos los procesos vean el contenido de los archivos de la misma manera que lo hace el núcleo, incluidos los buffers internos 1 .
Esto se implementa típicamente teniendo como máximo un búfer en el núcleo por objeto de archivo y para requerir que todo el acceso a los archivos pase por este búfer.
Si un proceso lee un archivo, el núcleo presentará el contenido del búfer al proceso, si la parte del archivo solicitado está actualmente en el búfer; si no es así, el núcleo buscará los datos del medio de almacenamiento subyacente y lo colocará dentro del búfer, luego volverá al paso anterior.
Si un proceso escribe en un archivo, los datos se colocan primero dentro del búfer en el núcleo para ese archivo. Finalmente, el contenido del búfer se vaciará al almacenamiento. Mientras tanto, el acceso de lectura se satisface desde el mismo búfer (ver arriba).
1 Al menos para archivos regulares, directorios y enlaces simbólicos. FIFOs y sockets son un asunto diferente ya que su contenido nunca se almacena de forma persistente de todos modos. Hay algunos casos especiales de archivos regulares cuyo contenido depende de quién pregunta; ejemplos son archivos en procfs y sysfs (piense
/proc/self
que es un enlace simbólico al ID del proceso del proceso que lee el enlace simbólico).fuente
mmap()
O_DIRECT, lo que puede provocar que las cosas no estén sincronizadas entre el disco y el caché de la página (pero eso resolverá en el momento en que el proceso que lo hace salga).Suponiendo que su comando es ejecutado por algún programa que usa la biblioteca de tiempo de ejecución C, en algún momento debería invocar
fclose
para cerrar el archivo abierto.La página del manual para la
fclose
función C dice:y la página de manual para
fflush
tiene la misma nota. La página del manualclose
dice:Tenga en cuenta que los datos están disponibles para otros procesos, incluso si no están sincronizados con la unidad. Tal vez eso ya sea lo suficientemente bueno para ti.
Si tiene dudas, escriba una prueba.
fuente
close()
llamada al sistema para cerrar el descriptor de un archivo.close
los archivos antes de salir (en programas hacky que no comprobar si hay errores); el kernel los limpiará y lo llamará efectivamenteclose
después de que su proceso falle.fclose
Sin embargo, es necesario que realice cualquier flujo stdio almacenado en el búfer, o deje que libc lo haga por ustedexit(3)
, en lugar de llamar directamente al sistema de salida.Sí. El shell abre el archivo de
echo
salida y lo envía directamente a eso. Una vez que sale el comando, está listo.Si los datos ya están en los medios es otra cuestión, lo que solo importa si después hay una falla de hardware, o si inspecciona la partición en vivo con algún software forense, sin pasar por el sistema de archivos montado.
No se preocupe, el núcleo solo mantiene una vista del archivo, independientemente de la frecuencia con la que se abre.
fuente
mmap(MAP_SHARED)
: las tiendas en la región mmaped no son coherentes con las lecturas del archivo (por ese hilo u otros procesos). Por esomsync(2)
existe. Al menos eso es lo que advierten las páginas del manual; dependiendo de la implementación, Linux en realidad puede asignar páginas físicas desde el caché de página, en cuyo caso supongo que básicamente es coherente (módulo de ordenamiento de memoria). De todos modos, todavía sucede todo antes_exit(2)
.Como regla general, cualquier dato que posea el kernel es mantenido y limpiado por el kernel, punto. Dichos datos incluyen datos transferidos a la memoria del kernel por una llamada al sistema como
write(2)
.Sin embargo, si su aplicación (por ejemplo, la biblioteca C) realiza el almacenamiento en búfer además de esto, entonces el núcleo obviamente no tiene idea y, por lo tanto, no garantiza su limpieza.
Además, no creo que haya ninguna garantía de tiempo para la limpieza; en general, se realiza con el "mejor esfuerzo" (léase: "cuando tengo un segundo").
fuente
waitpid()
regrese el proceso padre , si es que la limpieza ocurre. es decir, otros procesos no pueden observar directamente la finalización del proceso antes de cualquier modificación de archivo realizada por ese proceso. (Dije "directamente" para descartar la observación indirecta a través de las marcas de tiempo del archivo NFS, porque el almacenamiento en caché de NFS no es perfectamente coherente entre los hosts.)fsync
/fdatasync
, aunque la reescritura del búfer en Linux comenzará después de/proc/sys/vm/dirty_writeback_centisecs
centésimas de segundo (si no se retrasa por otro tráfico de E / S), y varios otros sintonizables en ese directorio procfs también afectan las cosas (por ejemplo, cómo grande para dejar crecer los búferes antes de hacer cualquier reescritura).No, no hay
Puede leer el contenido final del archivo justo después de que salga el comando; en su lugar, nunca leerá el archivo vacío. (En C y C ++, use las llamadas al sistema wait , waitpid , wait3 o wait4 para esperar a que el programa salga y solo luego lea el archivo. Si está utilizando un shell, otro lenguaje de programación o una biblioteca (por ejemplo, la biblioteca C sistema de llamada o la clase de proceso Java ), probablemente ya use una de estas llamadas del sistema).
Como lo han señalado otras respuestas y comentarios, puede terminar leyendo un archivo vacío después de la salida del programa si el programa ha salido sin vaciar sus memorias intermedias de salida (por ejemplo, debido a _exit , abortar o recibir una señal fatal, o porque es un programa Java que sale normalmente). Sin embargo, no hay nada que pueda hacer al respecto en este momento: los datos no vaciados se pierden para siempre, la espera adicional no los recuperará.
fuente
Sí
Perdón por tal vez agregar otra respuesta superflua, pero la mayoría parece centrarse en la pista falsa del título de la pregunta. Pero por lo que puedo decir, la pregunta no es sobre el almacenamiento intermedio, sino esto:
Si incondicionalmente. El uso de ">" que está describiendo, junto con "|" y "<", es el modelo de procesamiento basado en tubería en el que se basa el mundo de Unix y Linux. Encontrará cientos, si no miles de scripts totalmente dependiendo de este comportamiento en cada instalación de Linux.
Funciona según lo que desee por diseño, y si hubiera la más mínima posibilidad de una condición de carrera, se habría solucionado probablemente hace décadas.
fuente