echo
solo un semplice wrapper attorno a write
(questa è una semplificazione, vedere la modifica in basso per i dettagli cruenti), quindi per determinare se echo è atomico, è utile cercare la scrittura. Dal single UNIX specification:
atomica/non-atomica: Una scrittura è atomico se l'intero importo scritto in una sola operazione non è intervallata con i dati provenienti da qualsiasi altro processo. Questo è utile quando ci sono più scrittori che inviano dati a un singolo lettore. Le applicazioni devono sapere quanto è grande che una richiesta di scrittura possa essere eseguita atomicamente. Questo valore massimo è chiamato {PIPE_BUF}. Questo volume di IEEE Std 1003.1-2001 non dice se le richieste di scrittura per più di {PIPE_BUF} byte sono atomiche, ma richiede che le scritture di {PIPE_BUF} o meno byte siano atomiche.
È possibile controllare PIPE_BUF
sul proprio sistema con un semplice programma C. Se stai stampando una singola riga di output, non è ridicolmente lungo, dovrebbe essere atomico.
Ecco un semplice programma per controllare il valore di PIPE_BUF
:
#include <limits.h>
#include <stdio.h>
int main(void) {
printf("%d\n", PIPE_BUF);
return 0;
}
In Mac OS X, che mi dà 512 (il minimum allowed value per PIPE_BUF
). Su Linux, ottengo 4096. Quindi se le tue linee sono abbastanza lunghe, assicurati di controllarle sul sistema in questione.
modifica per aggiungere: Ho deciso di controllare the implementation of echo
in Bash, per confermare che verrà stampato atomicamente. Risulta che echo
utilizza putchar
o printf
a seconda se si utilizza l'opzione -e
. Si tratta di operazioni stdio memorizzate nel buffer, il che significa che riempiono un buffer e in realtà lo scrivono solo quando viene raggiunta una nuova riga (in modalità buffer di riga), il buffer viene riempito (in modalità bufferizzato) o si scarica esplicitamente l'output con fflush
. Per impostazione predefinita, un flusso sarà in modalità bufferizzata di linea se si tratta di un terminale interattivo e blocca la modalità bufferizzata se si tratta di un altro file. Bash non imposta mai il tipo di buffering, quindi per il tuo file di registro dovrebbe essere impostato in modo predefinito per bloccare la modalità di buffering. A quel punto, end of the echo
builtin, Bash calls fflush
per svuotare il flusso di output. Pertanto, l'output verrà sempre svuotato alla fine di echo
, ma potrebbe essere svuotato in precedenza se non si adatta al buffer.
La dimensione del buffer utilizzato può essere BUFSIZ
, sebbene possa essere diversa; BUFSIZ
è la dimensione predefinita se si imposta il buffer in modo esplicito utilizzando setbuf
, ma non esiste un modo portatile per determinare l'effettiva dimensione del buffer. Non ci sono anche linee guida portatili per ciò che è BUFSIZ
, ma quando l'ho provato su Mac OS X e Linux, era il doppio di PIPE_BUF
.
Che cosa significa tutto ciò? Poiché l'output di echo
è tutto bufferizzato, in realtà non chiama lo write
finché non viene riempito il buffer o viene chiamato fflush
. A quel punto, l'output dovrebbe essere scritto e si dovrebbe applicare la garanzia di atomicità di cui sopra. Se la dimensione del buffer stdout è maggiore di PIPE_BUF
, allora PIPE_BUF
sarà la più piccola unità atomica che può essere scritta. Se PIPE_BUF
è più grande della dimensione del buffer stdout, il flusso scriverà il buffer quando il buffer si riempie.
Quindi, echo
è garantita solo scrivere atomicamente sequenze più corte rispetto alla più piccola del PIPE_BUF
e la dimensione del buffer stdout, che è più probabile BUFSIZ
. Sulla maggior parte dei sistemi, lo BUFSIZ
è più grande di quello PIPE_BUF
.
tl; dr: echo
emetterà atomicamente le linee, a condizione che tali linee siano sufficientemente corte. Sui sistemi moderni, probabilmente sei sicuro fino a 512 byte, ma non è possibile determinarne il limite.
Non credo che bash sia lo strumento giusto per questo lavoro. Suggerirei qualcosa di più potente (perl, python, ruby ..) – Daenyth
Per inciso, se si dispone di un * lotto * di dati che vanno in questo registro, si potrebbe scoprire che aprire e chiudere continuamente il file di registro è una cattiva idea. Puoi aprire in modo permanente un file con 'exec 3 >> $ {LOG_FILE}' e poi scriverci ogni volta che vuoi con 'echo whatever> & 3'. Puoi chiudere il file con 'exec 3> & -', ma ciò avverrà quando lo script si chiude comunque. L'unico problema è che devi scegliere manualmente un numero per ogni file che apri e 0, 1 e 2 sono già stati presi. – ams