Открывает ли bash файлы в O_APPEND при использовании «>>» в Linux?

38

Если мы используем, echo 1234 >> some-fileто Документация говорит, что вывод добавлен.

Я предполагаю, что если некоторый файл не существует, то O_CREAT создаст новый файл. Если >был использован, то O_TRUNC будет обрезать существующий файл.

В случае >>: Будет ли файл открыт как O_WRONLY (или O_RDWR) и найден конец и операция записи выполнена, имитируя O_APPEND? Или файл будет открыт как O_APPEND, оставляя его ядру, чтобы убедиться, что добавление произойдет?

Я спрашиваю об этом, потому что процесс сохранения перезаписывает некоторые маркеры, вставленные с помощью echo, когда выходной файл находится в точке монтирования NFS, а в документации NFS говорится, что O_APPEND не поддерживается на сервере, поэтому ядру клиента придется с этим справляться. Я предполагаю, что процесс сохранения использует O_APPEND, но не уверен в bash >>на linux, поэтому задаю вопрос здесь.

Prem
источник
12
Проблема в NFS не в том, что O_APPENDона не поддерживается; проблема в том, что это эмулируется. В локальной файловой системе несколько процессов, выполняющих запись в один и тот же открытый файл O_APPEND , никогда не будут перезаписывать данные друг друга; в NFS O_APPENDэмулируется путем поиска до конца перед записью, что оставляет возможность состязаний. На NFS нет пути к этому; каждый параллельный писатель должен написать свой собственный файл. Единственный способ обойти это - настроить серверный процесс на NFS-сервере, сделать так, чтобы регистраторы входили в систему |nc server portи сервер добавлял входящие данные в журнал.
Гунтрам Блом поддерживает Монику
@GuntramBlohm, +1, спасибо за подтверждение. По сути, вы предлагаете использовать только один процесс записи в файл, и все другие процессы записи будут проходить через этот процесс.
Прем
Так много хороших ответов, Не уверен, какой ответ я должен принять. Сначала Брюс Эдигер показал, что используется O_APPEND. Далее Random832 показал, что это указано в стандартах. Наконец, Эрик Ренуф показал исходный код с тем же ответом. Все три перспективы добавляют к окончательной полной картине.
Прем
6
Короче говоря, NFS является грузом ошибок и не должен использоваться.
Р ..
2
Да, но мы уже узнали об этом, когда был изобретен O_EXCL.
Кевин

Ответы:

60

Я запустил это: strace -o spork.out bash -c "echo 1234 >> some-file"выяснить ваш вопрос. Вот что я нашел:

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

В каталоге, в котором я выполнял echoкоманду, не было файла с именем some-file .

Брюс Эдигер
источник
50

Это не только сделано в Bash, это требуется стандартом.

Из спецификации Unix :

При добавлении перенаправления вывода должен быть открыт файл, имя которого является результатом расширения слова, для вывода по указанному дескриптору файла. Файл открывается так, как если бы функция open (), определенная в томе «Системные интерфейсы» POSIX.1-2008, была вызвана с флагом O_APPEND. Если файл не существует, он должен быть создан.

Поэтому любая POSIX-совместимая оболочка должна это делать. В некоторых системах Unix это /bin/shможет быть не POSIX-оболочка Bourne (оболочка Bourne была изначально написана до того, как O_APPENDбыла изобретена), и обычно имеется доступная оболочка POSIX ksh, которая будет доступна shв другом месте пути, например в Solaris /usr/xpg4/bin.

Random832
источник
2
Интересно, что одной оболочкой, которая этого не делает, является оболочка Борна. Оболочка Bourne открывается без O_TRUNC и lseek () до конца. Это было бы потому, что он был написан до того, как был добавлен флаг O_APPEND open(). >>Сам был представлен своим предшественником оболочкой Томсона.
Стефан Шазелас
1
@ StéphaneChazelas Кроме того, я искал исходный код оболочки C для различных версий, и флаг O_APPEND не был представлен до 4.3BSD-Reno.
Random832
Он говорит «как будто», так что, не может ли он быть реализован по-другому (но с тем же наблюдаемым эффектом)? Не похоже, что стандарт требует использования O_APPEND, просто что-то, что ведет себя «как будто».
Томас,
1
@Thomas Это означает, что вы получите все документированное поведение для O_APPEND, что означает изменение положения в конце каждой записи. «Как будто» - это просто стандартное словосочетание, предназначенное для того, чтобы, например, его можно было открыть другими способами, помимо фактического вызова функции open () на нетрадиционных платформах Unix.
Random832
+1, чтобы показать, что это поведение в стандартах.
Прем
32

Глядя в источник, он использует O_APPEND. Для bash 4.3.30 в make_cmd.cстроке 710-713 читать:

case r_appending_to:                /* >>foo */
case r_append_err_and_out:          /* &>> filename */
  temp->flags = O_APPEND | O_WRONLY | O_CREAT;
  break;
Эрик Ренуф
источник
+1, для показа ответа с точки зрения исходного кода.
Прем
19

Давайте исследуем это, используя straceлокальную (не 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

Другие оболочки, а именно dash, dash, shиз BusyBox»и mkshведут себя точно так же.

Опция -e openозначает -e trace=openотслеживать только open()системный вызов.

Franklin Piat
источник