Czy bezpiecznie jest przekierowywać stdout i stderr do tego samego pliku bez kopii deskryptora pliku?


27

Zaczynam w pustym katalogu.

$ touch aFile
$ ls
aFile

Następnie mam lsdwa argumenty, z których jeden nie znajduje się w tym katalogu. Przekierowuję oba strumienie wyjściowe do pliku o nazwie output. Używam >>, aby uniknąć pisania jednocześnie.

$ ls aFile not_exist >>output 2>>output
$ cat output
ls: cannot access 'not_exist': No such file or directory
aFile

Co wydaje się działać. Czy są jakieś niebezpieczeństwa związane z tym podejściem?


6
To było szybkie głosowanie. Zajęło to pięć sekund. Czy możesz mi powiedzieć, w jaki sposób możesz tak szybko ocenić zasadność mojego pytania? A jeszcze lepiej, co jest z tym nie tak, żebym mógł to poprawić?
exit_status

Dlaczego nie zastosujesz ls aFile not_exist &>>outputtutaj bardziej standardowego ? (Uwaga,
zakładam,

5
Ponieważ to nie pomaga mi zrozumieć, o co pytam. Wiem, jak przekierować te strumienie do tego samego pliku, przenośnie nawet. Chcę wiedzieć, czy coś jest nie tak z tym, co zasugerowałem w pytaniu. @FedonKadifeli
exit_status

1
@FedonKadifeli &>>NIE jest standardem. Jest to DEPRECATED, niejednoznaczna składnia, która działa inaczej w różnych powłokach. Zastanawiam się, skąd macie swoje rzeczy.
Wujek Billy

4
Bash nie jest standardem . POSIX standardowych mandaty, które ls &>>foo ...powinny być analizowane jako dwa comands ls &i >>foo ..., a to jest droga inne muszle jakby /bin/shod Ubuntu są analizowania go. Ponieważ jest przestarzałe, możesz zajrzeć tutaj - chociaż nie udaję, że to jakikolwiek autorytet. Możesz jednak zapytać bashopiekunów, czy uważają to za dobry pomysł.
Wujek Billy

Odpowiedzi:


22

Nie, to nie jest tak bezpieczne jak standard >>bar 2>&1.

Kiedy piszesz

foo >>bar 2>>bar

otwierasz barplik dwa razy O_APPEND, tworząc dwa całkowicie niezależne obiekty pliku [1], każdy z własnym stanem (wskaźnik, tryby otwarte itp.).

Jest to bardzo odmienne od tego, 2>&1które wywołuje tylko wywołanie dup(2)systemowe i sprawia, że ​​stderr i stdout są wymiennymi aliasami dla tego samego obiektu pliku.

Jest z tym problem:

O_APPENDmoże prowadzić do uszkodzenia plików w systemach plików NFS, jeśli więcej niż jeden proces dołącza dane do pliku jednocześnie. Wynika to z faktu, że NFS nie obsługuje dołączania do pliku, więc jądro klienta musi go zasymulować, czego nie można zrobić bez warunków wyścigu.

Zazwyczaj można liczyć na prawdopodobieństwo pliku jak barw foo >>bar 2>&1zapisywany jest w tym samym czasie z dwóch różnych miejscach jest dość niska. Ale dzięki swojemu >>bar 2>>barzwiększyłeś go o kilkanaście rzędów wielkości, bez żadnego powodu.

[1] „Otwórz opisy plików” w języku POSIX.


3
Formalnie w przypadku plików w trybie dołączania jest to bezpieczne . Cytowany problem dotyczy błędu w systemie plików NFS, co powoduje, że nie nadaje się (jako niezgodny z POSIX) jako system plików. W przypadku trybu bez dołączania nigdy nie jest to bezpieczne.
R ..

1
To nie ma znaczenia. Podwójny dodatek OP nie jest bezpieczny w użyciu (poza tym, że jest całkowicie bezcelowy). I tak O_APPENDjest trochę badziewny - dość uciążliwy do prawidłowego wdrożenia.
mosvy

Uważam, że warunki wyścigu NFS dotyczą tylko różnych klientów. System operacyjny klienta powinien koordynować wszystkie operacje zapisu między procesami.
Barmar

@Barmar byłoby to prawdą, gdyby system operacyjny klienta dbał tylko o własny widok pliku NFS. Ale podczas zapisywania do pliku NFS otwartego za pomocą O_APPEND, klient najpierw pobierze „prawdziwy” rozmiar pliku z serwera („ponownie zweryfikuje” i-węzeł), a następnie dokona aktualizacji i-węzła seek + write + z pamięci podręcznej, a tylko ostatnia część jest wykonywane pod blokadami, co oznacza, że ​​pierwsza część nadal może pobrać przestarzały rozmiar z serwera i zastąpić poprawny z lokalnego węzła / pamięci podręcznej. Ten sam problem z lseek(SEEK_END).
mosvy

Nadal nie rozumiem, jak mogłoby to spowodować warunki wyścigu między dwoma strumieniami na tym samym kliencie. Oba strumienie powinny odnosić się do tego samego lokalnego i-węzła buforowanego.
Barmar

22

Co się stanie, kiedy to zrobisz?

some_command >>file 2>>file

jest to, że filezostanie otwarte do dodawania dwa razy. Można to bezpiecznie zrobić w systemie plików POSIX. Każdy zapis, który stanie się z plikiem, gdy zostanie otwarty w celu dołączenia, nastąpi na końcu pliku, niezależnie od tego, czy dane przechodzą przez standardowy strumień wyjściowy, czy standardowy strumień błędów.

Zależy to od obsługi operacji zapisu z dołączaniem atomowym w bazowym systemie plików. Niektóre systemy plików, takie jak NFS, nie obsługują dołączania atomowego. Zobacz np. Pytanie „Czy plik dołącza atom w systemie UNIX?” Na StackOverflow.

Za pomocą

some_command >>file 2>&1

działałby nawet na NFS.

Jednak za pomocą

some_command >file 2>file

nie jest bezpieczne, ponieważ powłoka obetnie plik wyjściowy (dwukrotnie), a każde zapisanie w jednym ze strumieni spowoduje zastąpienie danych już zapisanych przez inny strumień.

Przykład:

$ { echo hello; echo abc >&2; } >file 2>file
$ cat file
abc
o

helloCiąg jest napisany pierwszy (z kończącego znaku nowej linii), a następnie ciąg abcnastępuje linii jest napisane z błędem standardowym, zastępowanie hell. Wynikiem jest ciąg abcz nową linią, po której następuje resztka pierwszego echowyniku, ooraz nowa linia.

Zamiana dwóch echowokół rany produkuje tylko hellow pliku wyjściowym, ponieważ ten ciąg jest zapisywany jako ostatni i jest dłuższy niż abcciąg. Kolejność przekierowań nie ma znaczenia.

Lepiej i bezpieczniej byłoby używać bardziej idiomatycznych

some_command >file 2>&1

1
Chociaż dotyczy to współczesnych powłok, nie było tak w przypadku powłoki Bourne'a lub Thomsona (skąd >>pochodzi), gdzie >>można by je pisać i szukać do końca (przypuszczam, ponieważ O_APPEND nie było jeszcze wtedy wynalezione). Nawet w systemie Solaris 10 /bin/sh -c '(echo a; echo b >&2) >> file 2>> file; cat file'wyjścia b.
Stéphane Chazelas

@ StéphaneChazelas Czy to jest problem z implementacją shlub systemem plików Solaris 10 ?
Kusalananda

1
To właśnie >>pierwotnie robił, nie otwierał się z O_APPEND, otwierał się bez i szukał do końca. Nie jest to aż tak duży problem, tylko to, co robił i co zostało udokumentowane.
Stéphane Chazelas

0

To zależy od tego, co chcesz osiągnąć. To Ty decydujesz, czy możesz mieć błędy w tym samym pliku, co wynik. To jest po prostu zapisywanie tekstu w pliku z funkcjonalnością powłoki, która pozwala na przekierowanie, jak chcesz. Nie ma absolutnego tak lub nie. Jak wszystko w Linuksie można to zrobić na kilka sposobów, to jest mój sposób ls notExistingFile existingFile >> output 2>&1 Aby odpowiedzieć na pytanie: Jeśli chodzi o samo przekierowanie, tak jest całkowicie bezpieczne.


Jest w tym coś więcej niż to, co tu mówisz. To samo ćwiczenie >zamiast >>zastąpi niektóre znaki. Więc nie chodzi tylko o to, że powłoka pozwala mi przekierowywać, ponieważ kiedy przekierowuję za pomocą >, rezultat jest inny. Są więc niuanse >, czy są jakieś >>?
exit_status

Tak, będzie inaczej. Jak powiedziałem, zależy to od twojego celu >- nadpisania. >>- dołącz
Anioł
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.