Ответ 1
echo
просто простая обертка вокруг write
(это упрощение, см. ниже), чтобы определить, является ли echo атомарным, полезно искать запись. Из единой спецификации UNIX:
Атомный/неатомный: запись является атомарной, если вся сумма, записанная в одной операции, не чередуется с данными из любого другого процесса. Это полезно, когда несколько авторов отправляют данные одному читателю. Приложениям необходимо знать, как большой запрос на запись может выполняться атомарно. Этот максимум называется {PIPE_BUF}. Этот объем IEEE Std 1003.1-2001 не говорит, являются ли запросы на запись более чем для {PIPE_BUF} байтов атомарными, но требует, чтобы записи {PIPE_BUF} или меньшее количество байтов были атомарными.
Вы можете проверить PIPE_BUF
на вашей системе с помощью простой программы на языке C. Если вы просто печатаете одну строку вывода, это не смешно долго, она должна быть атомарной.
Вот простая программа для проверки значения PIPE_BUF
:
#include <limits.h>
#include <stdio.h>
int main(void) {
printf("%d\n", PIPE_BUF);
return 0;
}
В Mac OS X это дает мне 512 (минимальное допустимое значение для PIPE_BUF
). В Linux я получаю 4096. Поэтому, если ваши строки довольно длинные, убедитесь, что вы проверяете их в рассматриваемой системе.
изменить для добавления: я решил проверить реализацию echo
в Bash, чтобы подтвердить, что он будет печатать атомарно, Оказывается, echo
использует putchar
или printf
в зависимости от того, используете ли вы параметр -e
. Это буферизованные операции stdio, что означает, что они заполняют буфер и фактически записывают его только при достижении новой строки (в режиме буферизации в строке), буфер заполняется (в режиме с буферизацией) или вы явно скрываете выход с fflush
. По умолчанию поток будет в режиме буферизации в строке, если он является интерактивным терминалом, и блокирует буферный режим, если это любой другой файл. Bash никогда не устанавливает тип буферизации, поэтому для вашего файла журнала он должен по умолчанию блокировать режим буферизации. Затем конец echo
встроенный, Bash вызывает fflush
, чтобы очистить выходной поток, Таким образом, вывод всегда будет очищаться в конце echo
, но может быть сброшен раньше, если он не помещается в буфер.
Размер используемого буфера может быть BUFSIZ
, хотя он может быть другим; BUFSIZ
- это размер по умолчанию, если вы явно устанавливаете буфер с помощью setbuf
, но нет никакого переносного способа определить фактический размер вашего буфера. Также нет портативных руководств для того, что BUFSIZ
, но когда я тестировал его на Mac OS X и Linux, он был в два раза меньше PIPE_BUF
.
Что все это значит? Поскольку вывод echo
буферизуется, он фактически не вызывает write
до тех пор, пока буфер не будет заполнен или не будет вызван fflush
. В этот момент вывод должен быть записан, и должна быть указана гарантия атомарности, упомянутая выше. Если размер буфера stdout больше, чем PIPE_BUF
, то PIPE_BUF
будет наименьшей атомной единицей, которая может быть выписана. Если PIPE_BUF
больше размера буфера stdout, тогда поток будет выписывать буфер, когда буфер заполняется.
Таким образом, echo
гарантируется, что атомарно записывает последовательности короче, чем меньше PIPE_BUF
, и размер буфера stdout, что наиболее вероятно BUFSIZ
. В большинстве систем BUFSIZ
больше, чем PIPE_BUF
.
tl; dr: echo
будет атомарно выводить строки, если эти линии достаточно коротки. В современных системах вы, вероятно, можете хранить до 512 байт, но невозможно определить предел портативно.