Bash ouvre-t-il des fichiers dans O_APPEND lors de l’utilisation de «>>» sur linux?

38

Si nous utilisons echo 1234 >> some-filealors Documentation dit que la sortie est ajoutée.

Je suppose que si un fichier n'existe pas, alors O_CREAT créera un nouveau fichier. Si a >été utilisé, alors O_TRUNC tronquera le fichier existant.

Dans le cas de >>: Le fichier sera-t-il ouvert en tant que O_WRONLY (ou O_RDWR) et la fin de l'opération recherchée, l'opération d'écriture est effectuée, en simulant O_APPEND? Ou le fichier sera-t-il ouvert en tant que O_APPEND, laissant au noyau le soin de s'assurer que l'ajout se produit?

Je vous pose cette question car un processus de conservation remplace certains marqueurs insérés par echo, lorsque le fichier de sortie provient du point de montage NFS. La documentation NFS indique que O_APPEND n'est pas pris en charge sur le serveur. Le noyau du client devra donc le gérer. Je suppose que le processus de conservation utilise O_APPEND, mais n'est pas sûr de bash >>sur linux, posant donc la question ici.

Prem
la source
12
Le problème sur NFS n’est pas que ce O_APPENDn’est pas supporté; le problème est qu'il est imité. Sur un système de fichiers local, plusieurs processus écrivant dans le même fichier ouvert avec O_APPEND ne seront jamais écraser les données de chacun; sur NFS, O_APPENDest imité en cherchant jusqu'au bout avant d'écrire, ce qui laisse la possibilité de conditions de concurrence. Il n'y a aucun moyen de contourner cela sur NFS; chaque rédacteur parallèle doit écrire son propre fichier. La seule façon de contourner ce problème consiste à configurer un processus serveur sur le serveur NFS, à enregistrer les enregistreurs |nc server portet à faire en sorte que le serveur ajoute les données entrantes au journal.
Guntram Blohm soutient Monica
@GuntramBlohm, +1, merci pour la confirmation. Fondamentalement, votre suggestion est d'utiliser un seul processus d'écriture pour le fichier et tous les autres processus d'écriture suivront ce processus.
Prem
Tant de bonnes réponses, je ne sais pas quelle réponse je devrais accepter. Tout d'abord, Bruce Ediger a montré que O_APPEND est utilisé. Next Random832 a montré que cela est indiqué dans les normes. Finalement, Eric Renouf a montré le code source avec la même réponse. Les trois perspectives complètent l’image finale.
Prem
6
En bref, NFS est une charge de bogues et ne doit pas être utilisé.
R ..
2
Oui, mais nous l’avions déjà appris lorsqu’O_EXCL a été inventé.
Kevin

Réponses:

60

J'ai couru ceci: strace -o spork.out bash -c "echo 1234 >> some-file"pour comprendre votre question. C'est ce que j'ai trouvé:

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

Aucun fichier nommé "some-file" n'existait dans le répertoire dans lequel j'ai exécuté la echocommande.

Bruce Ediger
la source
50

Ce n'est pas seulement fait dans Bash, c'est requis par la norme.

A partir de la spécification Single Unix :

La redirection de sortie ajoutée entraîne l'ouverture du fichier dont le nom résulte de l'expansion du mot à la sortie sur le descripteur de fichier désigné. Le fichier est ouvert comme si la fonction open () définie dans le volume Interfaces système de POSIX.1-2008 était appelée avec l'indicateur O_APPEND. Si le fichier n'existe pas, il doit être créé.

Tout shell compatible POSIX doit donc le faire. Sur certains systèmes Unix, il /bin/shpeut s’agir d’un shell Bourne non POSIX (le shell Bourne a été écrit avant d’ O_APPENDêtre inventé), et le shell POSIX disponible le sera généralement ksh, qui sera disponible shdans un emplacement différent, tel que celui de Solaris /usr/xpg4/bin.

Au hasard832
la source
2
Fait intéressant, un shell qui ne le fait pas est le shell Bourne. Le shell Bourne s'ouvre sans O_TRUNC et lseek () s jusqu'à la fin. Ce serait parce qu'il a été écrit avant que l'indicateur O_APPEND ne soit ajouté à open(). >>elle-même a été introduite par son prédécesseur, le shell Thomson.
Stéphane Chazelas
1
@ StéphaneChazelas En outre, j'ai consulté le code source du shell C pour obtenir différentes versions et l'indicateur O_APPEND n'a été introduit que le 4.3BSD-Reno.
Random832
Il dit "comme si", donc ne pourrait-il pas être mis en œuvre différemment (tout en produisant le même effet observable)? Il ne semble pas que la norme nécessite l'utilisation de O_APPEND, mais simplement quelque chose qui se comporte "comme si".
Thomas
1
@Thomas Cela signifie que vous allez avoir tous les comportements documentés pour O_APPEND, ce qui signifie un repositionnement à la fin de chaque écriture. Le "comme si" est juste un verbiage de normes destiné à permettre par exemple son ouverture par d'autres moyens que l'appel en cours de la fonction open () sur des plates-formes Unix non traditionnelles.
Random832
+1, pour montrer que ce comportement est dans les normes.
Prem
32

En regardant dans le source, il utilise O_APPEND. Pour bash 4.3.30 à la make_cmd.cligne 710-713, lire:

case r_appending_to:                /* >>foo */
case r_append_err_and_out:          /* &>> filename */
  temp->flags = O_APPEND | O_WRONLY | O_CREAT;
  break;
Eric Renouf
la source
+1, pour afficher la réponse du point de vue du code source.
Prem
19

Examinons cela en utilisant straceun système de fichiers local (non-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

D' autres coquilles, à savoir dash, dash, shde busybox » et mkshse comportent de la même façon.

L'option -e opensignifie -e trace=openne tracer que l' open()appel système.

Franklin Piat
la source