Когда я перенаправлю вывод команды в файл (например, echo Hello > file
), будет ли этот файл иметь такие данные сразу после завершения команды? Или все еще очень маленькое окно между выходами команды и данными, записанными в файл? Я хотел бы прочитать файл сразу после выхода из команды, но я не хочу читать пустой файл.
21
echo
и>
не отдельные (недолговечные) процессы? И где выводecho
остается до того,>
как выполняется?>
- перенаправление оболочки. Это так же, как если бы программа открыла именованный файл для записи и заменила на него стандартный вывод, что в точности и делает оболочка.file
содержимогоHello
независимо от того, очищено оно или нет.Ответы:
Есть несколько слоев буферов / кэшей.
Кэш процессора.
Данные складываются побайтно и сохраняются в кэше процессора. Если кэш-память ЦП заполнена и данные не были доступны в течение некоторого времени, блок, содержащий наши данные, может быть записан в основную память. По большей части они скрыты от разработчиков приложений.
Внутрипроцессные буферы.
В процессе сбора данных выделяется некоторая память, поэтому нам нужно сделать как можно меньше запросов к ОС, поскольку это сравнительно дорого. Процесс копирует данные в эти буферы, которые снова могут быть защищены кэш-памятью ЦП, поэтому нет гарантии, что данные будут скопированы в основную память. Приложение должно явно очистить эти буферы, например, используя fclose (3) или fsync (3). Функция exit (3) также делает это до завершения процесса, в то время как функция _exit (2) этого не делает , поэтому на странице руководства есть большое предупреждение для этой функции, чтобы вызывать ее, только если вы знаете, что вы делает.
Буферы ядра
Затем ОС сохраняет свой собственный кэш, чтобы минимизировать количество запросов, которые необходимо отправить на диски. Этот кэш не относится ни к каким процессам, в частности, поэтому данные в нем могут принадлежать процессам, которые уже закончили, и, поскольку все обращения осуществляются здесь, следующая программа увидит данные, если они достигли здесь. Ядро запишет эти данные на диски, когда у него будет время или когда это явно задано.
Кеш накопителя
Сами диски также хранят кеш для ускорения доступа. Они пишутся довольно быстро, и есть команда, чтобы записать оставшиеся данные в кэш-память и сообщить, когда это будет выполнено, которую ОС использует при завершении работы, чтобы убедиться, что никакие данные не остаются незаписанными до выключения питания.
Для вашего приложения достаточно, чтобы данные были зарегистрированы в буферах ядра (на данный момент фактические данные могут все еще находиться в кэше ЦП и, возможно, не были записаны в основную память): процесс «эхо» завершается, что означает, что любые внутрипроцессные буферы должны быть сброшены, а данные переданы в ОС, и при запуске нового процесса гарантируется, что ОС вернет те же данные при запросе.
источник
Если в приложении нет внутренних кэшей, изменения будут немедленно записаны в файл. То же самое для вашего примера. Файл является логической сущностью в памяти, которая будет немедленно обновлена. Любые последующие операции над файлом будут видеть изменения, сделанные программой.
Однако это не означает, что изменение было записано на физический диск. Изменения могут остаться в кэшах файловой системы ОС или аппаратных кешах. Чтобы очистить буферы файловой системы, используйте
sync
команду.Вы не должны столкнуться с какими-либо практическими проблемами здесь.
источник
exit
он по крайней мере не вызывается неявно). Другие библиотеки / языки (например, Java!) Дают меньше гарантий.В общем, ответ - нет .
Это зависит от команды. Как уже упоминалось в других ответах, если команда не выполняет внутреннюю буферизацию данных, все данные будут доступны после ее завершения.
Но большинство, если не все, библиотеки стандарта ввода / вывод этого буфер стандартного вывода по умолчанию (в некоторой степень), и дают разные гарантии о автоматической промывке буферов , когда Замкнутых приложения.
C гарантирует, что нормальный выход очистит буферы . «Нормальный выход» означает, что
exit
вызывается - либо явно, либо путем возврата изmain
. Однако ненормальный выход может обойти этот вызов (и, следовательно, оставить неиспользованные буферы позади).Вот простой пример:
Если вы скомпилируете это и выполните его,
test
это не обязательно будет записано в стандартный вывод.Другие языки программирования дают еще меньше гарантий: Java, например, делает не автоматический флаш по окончанию программы . Если выходной буфер содержит неопределенную строку, он может быть потерян, если не
System.out.flush()
был вызван явно.Тем не менее, ваше тело вопроса спрашивает что - то немного другое: если данные поступают в файл на всех , он должен сделать это сразу же после команды прекращается ( при условии предостережений , описанных в других ответах).
источник
write()
илиpwrite()
системный вызов произойдет до завершения процесса, и именно тогда изменения файла станут видимыми. Таким образом, последнее изменение файла определенно перед завершением процесса, самое позднее, самое позднее. Я думаю, что даже сmmap(MAP_SHARED)
файлом невозможно наблюдать завершение процесса до того, как произойдут все изменения файла.Я думаю, что ни один вопрос еще не решает эту проблему достаточно:
Как объясняют другие ответы, хорошо работающая программа очищает свои внутренние файловые буферы до нормального завершения процесса . После этого данные могут все еще оставаться в буферах ядра или оборудования, прежде чем они будут записаны в постоянное хранилище. Однако семантика файловой системы Linux гарантирует, что все процессы видят содержимое файлов так же, как ядро, включая внутренние буферы 1 .
Обычно это реализуется с помощью не более одного буфера в ядре на объект файла и требует, чтобы весь доступ к файлу проходил через этот буфер.
Если процесс читает файл, ядро представит процессу содержимое буфера, если запрошенная часть файла в данный момент находится в буфере; если это не так, ядро извлечет данные с основного носителя и поместит их в буфер, а затем вернется к предыдущему шагу.
Если процесс записывает в файл, данные сначала помещаются в буфер ядра для этого файла. Со временем содержимое буфера будет сброшено в хранилище. В то же время доступ для чтения удовлетворяется из того же буфера (см. Выше).
1 По крайней мере для обычных файлов, каталогов и символических ссылок. FIFO и сокеты - это другое дело, поскольку их содержимое никогда не хранится постоянно. Есть несколько особых случаев обычных файлов, содержимое которых зависит от того, кто спрашивает; примерами являются файлы в procfs и sysfs (представьте,
/proc/self
что это символическая ссылка на идентификатор процесса, читающего символическую ссылку).источник
mmap()
O_DIRECT, что может привести к несинхронизации между диском и кэшем страницы (но это разрешит момент, когда процесс, выполняющий это, завершится).Предполагая, что ваша команда выполняется какой-либо программой, использующей библиотеку времени выполнения C, в какой-то момент она должна вызвать
fclose
закрытие открытого файла.Страница man для
fclose
функции C говорит:и страница man для
fflush
того же примечания. Страница руководства дляclose
говорит:Обратите внимание, что данные доступны другим процессам, даже если они не синхронизированы с диском. Может быть, это уже достаточно хорошо для вас.
Если вы сомневаетесь, напишите тест.
источник
close()
системный вызов для закрытия дескриптора файла.close
файлы перед выходом (в Hacky программ , которые не проверяют на наличие ошибок); ядро очистит их, фактически вызвавclose
вас после того, как ваш процесс завершится. Однако вам нужно использоватьfclose
любые буферизованные потоки stdio или позволить libc сделать это за васexit(3)
, в отличие от системного вызова exit.Да. Оболочка открывает выходной файл и
echo
выводит непосредственно на него. После выхода из команды все готово.Если данные уже находятся на носителе, это другой вопрос, который имеет значение только в случае, если после этого произойдет сбой оборудования, или вы проверяете работающий раздел с помощью какого-либо криминалистического программного обеспечения, минуя смонтированную файловую систему.
Не волнуйтесь, ядро хранит только один просмотр файла, независимо от того, как часто он открывается.
источник
mmap(MAP_SHARED)
: хранилища в области mmaped не согласованы с чтениями файла (этим потоком или другими процессами). Вот почемуmsync(2)
существует. По крайней мере, об этом предупреждают man-страницы; в зависимости от реализации, Linux может фактически отображать физические страницы из кэша страниц, и в этом случае я бы предположил, что он в основном является последовательным (по модулю упорядочения памяти). Во всяком случае, это все еще происходит раньше_exit(2)
.Как правило, любые данные, принадлежащие ядру , поддерживаются и очищаются ядром, точка. Такие данные включают в себя данные, передаваемые в память ядра системным вызовом, таким как
write(2)
.Однако, если ваше приложение (например, библиотека C) выполняет буферизацию поверх этого, тогда ядро, очевидно, не имеет представления и, следовательно, не гарантирует его очистку.
Более того, я не верю, что есть какая-то временная гарантия для очистки - она, как правило, выполняется на основе «максимальных усилий» (читай: «когда у меня есть секунда»).
источник
waitpid()
возврата родительского процесса , если очистка вообще произойдет. то есть другие процессы не могут непосредственно наблюдать завершение процесса до того, как какие-либо изменения файла будут выполнены этим процессом. (Я сказал «напрямую», чтобы исключить косвенное наблюдение через временные метки файлов NFS, потому что кэширование NFS не идеально согласовано между хостами.)fsync
/fdatasync
, хотя обратная запись буфера в Linux начнется через/proc/sys/vm/dirty_writeback_centisecs
сотые доли секунды (если не задерживается другим трафиком ввода-вывода), и различные другие переменные в этом каталоге procfs также влияют на вещи (например, как большой, чтобы буферы росли перед выполнением обратной записи).Нет, нет
Вы можете прочитать окончательное содержимое файла сразу после завершения команды, вместо этого вы никогда не будете читать пустой файл. (В C и C ++ используйте системные вызовы wait , waitpid , wait3 или wait4, чтобы дождаться завершения программы и только затем прочитать файл. Если вы используете оболочку, другой язык программирования или библиотеку (например, библиотека C система вызовов или класс процесса Java ), возможно, он уже использует один из этих системных вызовов.)
Как и другие ответы и комментарии указали, вы можете закончить чтение пустой файл после выхода из программы , если программа завершается без промывки его внутренние буферы вывода (например , из - за _exit , прерывания или получения фатального сигнала, или потому , что это Java-программа выходит нормально). Однако на этом этапе вы ничего не можете с этим поделать: незагрязненные данные будут потеряны навсегда, дополнительное ожидание не восстановит их.
источник
да
Извините за добавление еще одного лишнего ответа, но большинство, кажется, сосредоточено на красной сельди заголовка вопроса. Но, насколько я могу судить, вопрос вовсе не в буферизации, а в следующем:
Да, безусловно. Использование ">", которое вы описываете, вместе с "|" и «<» - это модель обработки на основе каналов, на которой в значительной степени основаны мир Unix и Linux. В каждой установке Linux вы найдете сотни, если не тысячи сценариев, полностью зависящих от этого поведения.
Он работает так, как вы хотите для каждого дизайна, и если бы была хоть малейшая вероятность состояния гонки, это было бы исправлено, вероятно, десятилетия назад.
источник