¿Bash abre archivos en O_APPEND cuando usa ">>" en Linux?

38

Si usamos, echo 1234 >> some-fileentonces la documentación dice que la salida se agrega.

Supongo que si algún archivo no existe, O_CREAT creará un nuevo archivo. Si >se utilizó, entonces O_TRUNC truncará el archivo existente.

En caso de >>: ¿Se abrirá el archivo como O_WRONLY (u O_RDWR) y se buscará que finalice y se complete la operación de escritura, simulando O_APPEND? ¿O se abrirá el archivo como O_APPEND, dejándolo en el kernel para asegurarse de que se agregue?

Pregunto esto porque un proceso de conservación está sobrescribiendo algunos marcadores insertados por echo, cuando el archivo de salida es del punto de montaje NFS, y la documentación de NFS dice que O_APPEND no es compatible con el servidor, por lo que el núcleo del cliente tendrá que manejarlo. Supongo que el proceso de conservación está usando O_APPEND, pero no estoy seguro de bash >>en Linux, por lo tanto, haga la pregunta aquí.

Prem
fuente
12
El problema en NFS no O_APPENDes que no sea compatible; El problema es que es emulado. En un sistema de archivos local, varios procesos que escriben en el mismo archivo abierto O_APPEND nunca sobrescribirán los datos del otro; en NFS, O_APPENDse emula buscando hasta el final antes de escribir, lo que deja la posibilidad de condiciones de carrera. No hay forma de evitar esto en NFS; cada escritor paralelo necesita escribir su propio archivo. La única forma de evitar esto es configurar un proceso de servidor en el servidor NFS, hacer que los registradores inicien sesión |nc server porty que el servidor agregue datos entrantes al registro.
Guntram Blohm apoya a Monica
@GuntramBlohm, +1, gracias por la confirmación. Básicamente, su sugerencia es utilizar solo un proceso de escritura en el archivo, y todos los demás procesos de escritura pasarán por este proceso.
Prem
Tantas buenas respuestas, No estoy seguro de qué respuesta debo aceptar. Primero Bruce Ediger mostró que se utiliza O_APPEND. A continuación, Random832 mostró que esto se da en los estándares. Finalmente, Eric Renouf mostró el código fuente con la misma respuesta. Las tres perspectivas se suman a la imagen completa final.
Prem
66
En resumen, NFS es una carga de errores y no debe usarse.
R ..
2
Sí, pero eso ya lo aprendimos cuando se inventó O_EXCL.
Kevin

Respuestas:

60

Ejecuté esto: strace -o spork.out bash -c "echo 1234 >> some-file"para resolver su pregunta. Esto es lo que encontré:

open("some-file", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3

No existía ningún archivo llamado "algún archivo" en el directorio en el que ejecuté el echocomando.

Bruce Ediger
fuente
50

Esto no solo se hace en Bash, sino que también lo exige el estándar.

De la especificación Single Unix :

La redirección de salida agregada hará que el archivo cuyo nombre resulta de la expansión de la palabra se abra para la salida en el descriptor de archivo designado. El archivo se abre como si se llamara a la función open () como se define en el volumen de Interfaces del sistema de POSIX.1-2008 con el indicador O_APPEND. Si el archivo no existe, se creará.

Por lo tanto, cualquier shell compatible con POSIX debe hacerlo. En algunos sistemas Unix, /bin/shpuede ser un shell Bourne que no sea POSIX (el shell Bourne se escribió originalmente antes de que O_APPENDse inventara), y el shell POSIX disponible normalmente kshestará disponible shen una ubicación de ruta diferente, como la de Solaris /usr/xpg4/bin.

Aleatorio832
fuente
2
Curiosamente, un shell que no lo hace es el shell Bourne. El shell Bourne se abre sin O_TRUNC y lseek () s hasta el final. Eso sería porque se escribió antes de que se agregara el indicador O_APPEND open(). >>en sí fue introducido por su predecesor, el shell Thomson.
Stéphane Chazelas
1
@ StéphaneChazelas Además, busqué la fuente de shell C para varias versiones, y el indicador O_APPEND no se introdujo hasta 4.3BSD-Reno.
Random832
Dice "como si", entonces ¿no podría implementarse de manera diferente (pero produciendo el mismo efecto observable)? No parece que el estándar requiera el uso de O_APPEND, solo algo que se comporte "como si".
Thomas
1
@Thomas Significa que obtendrá todo el comportamiento documentado para O_APPEND, lo que significa reposicionamiento al final de cada escritura. El "como si" es solo un lenguaje estándar que permite, por ejemplo, que se abra por algún otro medio que no sea llamar a la función open () en plataformas Unix no tradicionales.
Random832
+1, por mostrar que este comportamiento está en los estándares.
Prem
32

Mirando en la fuente, usa O_APPEND. Para bash 4.3.30 en la make_cmd.clínea 710-713, lea:

case r_appending_to:                /* >>foo */
case r_append_err_and_out:          /* &>> filename */
  temp->flags = O_APPEND | O_WRONLY | O_CREAT;
  break;
Eric Renouf
fuente
+1, para mostrar la respuesta desde la perspectiva del código fuente.
Prem
19

Investiguemos eso usando straceen un sistema de archivos local (no NFS):

$ strace -eopen -- bash -c "echo foo >> /tmp/testfile000" 2>&1 | grep /tmp/testfile000
open("/tmp/testfile000", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3

$ strace -eopen -- bash -c "echo foo > /tmp/testfile000" 2>&1 | grep /tmp/testfile000
open("/tmp/testfile000", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3

Otros proyectiles, es decir dash, dash, shde busybox' y mkshse comportan de la misma manera.

La opción -e opensignifica -e trace=openrastrear solo la open()llamada al sistema.

Franklin Piat
fuente