Czy bash otwiera pliki w O_APPEND, gdy używasz „>>” w systemie Linux?

38

Jeśli użyjemy, echo 1234 >> some-filewówczas Dokumentacja mówi, że wynik jest dołączany.

Domyślam się, że jeśli jakiś plik nie istnieje, O_CREAT utworzy nowy plik. Jeśli >został użyty, O_TRUNC obetnie istniejący plik.

W przypadku >>: Czy plik zostanie otwarty jako O_WRONLY (lub O_RDWR) i nastąpi próba zakończenia, a operacja zapisu zostanie wykonana, symulując O_APPEND? A może plik zostanie otwarty jako O_APPEND, pozostawiając go jądrze, aby upewnić się, że nastąpi dołączenie?

Pytam o to, ponieważ proces konserwatora zastępuje niektóre znaczniki wstawione przez echo, gdy plik wyjściowy pochodzi z punktu montowania NFS, a Dokumentacja NFS mówi, że O_APPEND nie jest obsługiwany na serwerze, więc jądro klienta będzie musiało to obsłużyć. Wydaje mi się, że proces konserwatora używa O_APPEND, ale nie jestem pewien bash >>na Linuksie, stąd zadaje pytanie tutaj.

Prem
źródło
12
Problem w NFS nie jest taki, że O_APPENDnie jest obsługiwany; problem polega na tym, że jest emulowany. W lokalnym systemie plików kilka procesów zapisujących do tego samego otwartego pliku O_APPEND nigdy nie nadpisuje danych; na NFS, O_APPENDjest emulowany przez dążenie do końca przed napisaniem, co pozostawia możliwość warunków wyścigowych. W NFS nie można tego obejść; każdy piszący równolegle musi napisać własny plik. Jedynym sposobem obejścia tego problemu jest skonfigurowanie procesu serwera na serwerze NFS, zalogowanie rejestratorów |nc server porti włączenie przez serwer danych przychodzących do dziennika.
Guntram Blohm wspiera Monikę
@GuntramBlohm, +1, dzięki za potwierdzenie. Zasadniczo sugerujesz użycie tylko jednego procesu zapisującego do pliku, a wszystkie inne procesy zapisujące przejdą przez ten proces.
Prem
Tak wiele dobrych odpowiedzi, Nie jestem pewien, którą odpowiedź powinienem zaakceptować. Najpierw Bruce Ediger wykazał, że używany jest O_APPEND. Następnie Random832 pokazał, że jest to podane w standardach. Wreszcie Eric Renouf pokazał kod źródłowy z tą samą odpowiedzią. Wszystkie trzy perspektywy dodają do ostatecznego pełnego obrazu.
Prem
6
Krótko mówiąc, NFS to mnóstwo błędów i nie należy go używać.
R ..
2
Tak, ale już się tego nauczyliśmy, kiedy wynaleziono O_EXCL.
Kevin

Odpowiedzi:

60

Uruchomiłem to: strace -o spork.out bash -c "echo 1234 >> some-file"aby dowiedzieć się, jakie masz pytanie. Oto co znalazłem:

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

W katalogu, w którym uruchomiłem echopolecenie, nie istniał żaden plik o nazwie „jakiś plik” .

Bruce Ediger
źródło
50

Jest to nie tylko wykonywane w Bash, ale jest wymagane przez standard.

Ze specyfikacji Single Unix :

Dołączone przekierowanie danych wyjściowych spowoduje otwarcie pliku, którego nazwa wynika z rozwinięcia słowa, do wyświetlenia w wyznaczonym deskryptorze pliku. Plik jest otwierany tak, jakby funkcja open () zdefiniowana w woluminie interfejsów systemowych POSIX.1-2008 została wywołana z flagą O_APPEND. Jeśli plik nie istnieje, zostanie utworzony.

Dlatego każda powłoka zgodna z POSIX musi to zrobić. W niektórych systemach uniksowych /bin/shmoże być powłoką Bourne'a inną niż POSIX (powłoka Bourne'a została pierwotnie napisana przed O_APPENDwynalezieniem), a zwykle dostępna będzie powłoka POSIX ksh, która będzie dostępna jak shw innej lokalizacji ścieżki, takiej jak Solaris /usr/xpg4/bin.

Losowo 832
źródło
2
Co ciekawe, jedną powłoką, która tego nie robi, jest powłoka Bourne'a. Powłoka Bourne'a otwiera się bez O_TRUNC i lseek () s do końca. Byłoby tak, ponieważ został napisany przed dodaniem flagi O_APPEND open(). >>sam został wprowadzony przez swojego poprzednika, powłokę Thomsona.
Stéphane Chazelas
1
@ StéphaneChazelas Poszukałem również źródła powłoki C dla różnych wersji, a flaga O_APPEND została wprowadzona dopiero od 4.3BSD-Reno.
Random832
Mówi „jakby”, więc czy nie można go zaimplementować inaczej (ale przynosząc ten sam obserwowalny efekt)? Nie wydaje się, że standard wymaga użycia O_APPEND, tylko coś, co zachowuje się „jak gdyby”.
Thomas
1
@Thomas Oznacza to, że wszystkie zachowania zostaną udokumentowane dla O_APPEND, co oznacza zmianę położenia na końcu każdego zapisu. „Jak gdyby” jest tylko standardowym językiem, który ma na celu np. Otwarcie go w inny sposób niż faktyczne wywołanie funkcji open () na nietradycyjnych platformach uniksowych.
Random832
+1 za wykazanie, że takie zachowanie jest zgodne ze standardami.
Prem
32

Przeglądając źródło, używa O_APPEND. Dla bash 4.3.30 w make_cmd.clinii 710-713 czytamy:

case r_appending_to:                /* >>foo */
case r_append_err_and_out:          /* &>> filename */
  temp->flags = O_APPEND | O_WRONLY | O_CREAT;
  break;
Eric Renouf
źródło
+1 za pokazanie odpowiedzi z perspektywy kodu źródłowego.
Prem
19

Zbadajmy, że stracew lokalnym systemie plików (innym niż 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

Inne pociski, a mianowicie dash, dash, shz Busybox”i mkshzachowują się tak samo.

Opcja -e openoznacza -e trace=openśledzenie tylko open()wywołania systemowego.

Franklin Piat
źródło