echo
просто обертка вокруг write
(это упрощение; подробности смотрите ниже в редактировании), поэтому, чтобы определить, является ли echo атомарным, полезно поискать в записи. Из одной спецификации UNIX :
Атомное / неатомарное: запись является атомарной, если все количество, записанное в одной операции, не чередуется с данными из любого другого процесса. Это полезно, когда несколько писателей отправляют данные одному читателю. Приложения должны знать, насколько большой запрос записи может быть выполнен атомарно. Этот максимум называется {PIPE_BUF}. В этом объеме IEEE Std 1003.1-2001 не говорится, являются ли запросы записи для более чем {PIPE_BUF} байтов атомарными, но требуется, чтобы записи {PIPE_BUF} или меньше байтов были атомарными.
Вы можете проверить PIPE_BUF
в своей системе с помощью простой программы на Си. Если вы просто печатаете одну строку вывода, это не до смешного длинного, оно должно быть атомарным.
Вот простая программа для проверки значения 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
1035 *, Bash вызывает fflush
для очистки выходного потока. Таким образом, вывод всегда будет сброшен в конце echo
, но может быть сброшен раньше, если он не помещается в буфер.
Размер используемого буфера может быть BUFSIZ
, хотя он может быть другим; BUFSIZ
- это размер по умолчанию, если вы устанавливаете буфер явно, используя setbuf
, но нет никакого портативного способа определить фактический размер вашего буфера. Также нет никаких портативных рекомендаций для того, что такое BUFSIZ
, но когда я тестировал его на Mac OS X и Linux, он был в два раза больше PIPE_BUF
.
Что все это значит? Поскольку все выходные данные echo
буферизуются, на самом деле они не будут вызывать write
до тех пор, пока не будет заполнен буфер или не будет вызван fflush
. В этот момент вывод должен быть записан, и должна применяться гарантия атомарности, о которой я упоминал выше. Если размер буфера стандартного вывода больше PIPE_BUF
, то PIPE_BUF
будет наименьшей атомарной единицей, которую можно записать. Если PIPE_BUF
больше, чем размер буфера стандартного вывода, тогда поток запишет буфер, когда буфер заполнится.
Таким образом, echo
гарантирует только атомарную запись последовательностей, которые короче, чем меньший из PIPE_BUF
и размер буфера stdout, который, скорее всего, BUFSIZ
. В большинстве систем BUFSIZ
больше PIPE_BUF
.
tl; dr : echo
будет атомарно выводить строки, если эти строки достаточно короткие. В современных системах вы, вероятно, безопасны до 512 байт, но невозможно определить предел переносимым образом.