Dlaczego zachowanie `polecenia 1> plik.txt 2> plik.txt` różni się od` polecenia 1> plik.txt 2> i 1`?


20

Jeśli chcesz przekierować stdout i stderr do tego samego pliku, możesz to zrobić za pomocą command 1>file.txt 2>&1, lub command &>file.txt. Ale dlaczego zachowanie command 1>file.txt 2>file.txtróżni się od powyższych dwóch poleceń?

Poniżej znajduje się polecenie weryfikacji.

$ cat redirect.sh
#!/bin/bash

{ echo -e "output\noutput" && echo -e "error" 1>&2; } 1>file.txt 2>&1
{ echo -e "output\noutput" && echo -e "error" 1>&2; } 1>file1.txt 2>file1.txt
{ echo -e "error" 1>&2 && echo -e "output\noutput"; } 1>file2.txt 2>file2.txt
{ echo -e "output" && echo -e "error\nerror" 1>&2; } 1>file3.txt 2>file3.txt
{ echo -e "error\nerror" 1>&2 && echo -e "output"; } 1>file4.txt 2>file4.txt

$ ./redirect.sh

$ echo "---file.txt---"; cat file.txt;\
echo "---file1.txt---"; cat file1.txt; \
echo "---file2.txt---"; cat file2.txt; \
echo "---file3.txt---"; cat file3.txt; \
echo "---file4.txt----"; cat file4.txt;
 ---file.txt---
output
output
error
---file1.txt---
error

output
---file2.txt---
output
output
---file3.txt---
error
error
---file4.txt----
output
rror

O ile wyniki są widoczne, wygląda na to, że drugi ciąg echa zastępuje pierwszy ciąg echa po uruchomieniu command 1>file.txt 2>file.txt, ale nie wiem, dlaczego tak się stanie. (Czy jest gdzieś referencja?)

Odpowiedzi:


43

Musisz wiedzieć dwie rzeczy:

  • Deskryptor otwartego pliku znany stronie procesu w trybie aplikacji odwołuje się do wewnętrznego obiektu jądra znanego jako opis pliku , który jest instancją otwartego pliku. W jednym pliku może znajdować się wiele opisów plików i wiele deskryptorów plików udostępniających opis pliku.
  • Aktualna pozycja plik jest atrybutem opisu pliku . Jeśli więc wiele deskryptorów plików mapuje się na opis jednego pliku, wszystkie mają tę samą bieżącą pozycję pliku, a zmiana pozycji pliku wprowadzona za pomocą jednego takiego deskryptora pliku wpływa na wszystkie inne takie deskryptory plików.

    Takie zmiany są uchwalone przez procesy Wywołanie read()/ readv(), write()/ writev(), lseek()połączeń systemowych i tym podobne. Do echowywołania komend write()/ writev()oczywiście.

Tak się dzieje:

  • command 1>file.txt 2>&1tworzy tylko jeden opis pliku, ponieważ powłoka otwiera plik tylko raz. Powłoka mapuje zarówno standardowe wyjście, jak i standardowe deskryptory plików błędów na opis tego pojedynczego pliku. To powiela standardowe wyjście na standardowe wyjście błędów. Zatem zapis za pomocą dowolnego deskryptora pliku przesunie współdzieloną bieżącą pozycję pliku: każdy zapis następuje po poprzednim zapisie wspólnego opisu pliku. I jak widać, wyniki echopoleceń nie zastępują się nawzajem.
  • command 1>file.txt 2>file.txttworzy dwa opisy plików, ponieważ powłoka dwukrotnie otwiera ten sam plik w odpowiedzi na dwa jawne przekierowania. Standardowe deskryptory plików wyjściowych i standardowych błędów mapują na dwa różne opisy plików, które z kolei mapują na ten sam pojedynczy plik. Dwa opisy plików mają całkowicie niezależne bieżące pozycje plików, a każdy zapis natychmiast przechodzi do poprzedniego zapisu tego samego opisu pliku. Jak widać, wynik jest taki, że to, co zostało napisane za pomocą jednego, może zastąpić to, co zostało napisane za pomocą innego, na różne sposoby, w zależności od kolejności wykonywania zapisów.

Dalsza lektura


1
Powinien być otwarty opis pliku, a nie opis pliku . Chodzi bardziej o zapis, w jaki sposób plik został otwarty bardziej niż sam plik. Taką terminologię stosuje przynajmniej dokumentacja POSIX, Linux, Solaris i GNU.
Stéphane Chazelas,

16

Użycie >powoduje, że plik zostanie zastąpiony. Ponieważ masz stdout i stderr zapisujące do pliku w dwóch różnych operacjach, ostatnia zapisująca zastąpi pierwszą.

Możesz to zrobić:

command 1>>file.txt 2>>file.txt

lub

command &>file.txt Tylko bash v4 i wyżej.

>> każe mu dołączyć plik, aby nie zastąpił danych wyjściowych poprzednich operacji.

&> jest po prostu łatwiejszym sposobem pisania 2>&1


2
dlaczego wyświetla ls 1>&0i ls 0>&0nadal wyświetla wynik działania ls?
Yvain,

Dziwię się, że używanie >>działa. Dlaczego nie ma to problemu z dwoma opisami plików z niezależnymi przesunięciami? @JdeBP, wiesz? Myślałem, że otwarcie pliku w trybie dołączania jest równoznaczne z otwarciem w trybie zapisu, szukaniem do ostatecznej pozycji, a następnie uniemożliwianiem dalszego wyszukiwania.
JoL

4
@jlmg: Pliki w trybie dołączania są widoczne, ale każdy zapis jest poprzedzony domyślnym szukaniem do końca. To, czy to domniemane poszukiwanie jest atomowe, jest dla mnie mniej jasne.
Kevin

1
Zależy to całkowicie od kolejnego pytania. Takie, które są powiązane, wskazują, że odpowiedź jest niekompletna. I jest mało prawdopodobne, aby ludzie sprawdzali kolejne pytania, nie chcąc również znać pełnej odpowiedzi. Dlatego jest całkiem prawdopodobne, że takie pytania będą zawierały odpowiedzi, które duplikują informacje, a tym samym zostaną zamknięte jako duplikaty.
trlkly 11.09.17

1
@ Kevin, w systemach plików w pełni zgodnych z POSIX, niejawne wyszukiwanie O_APPEND jest atomowe. To powiedziawszy, nie każdy system plików poprawnie implementuje odpowiednią semantykę - na przykład NFS (przynajmniej v3 i wcześniejszy - nie mam jasności na v4) nie ma odpowiedniej obsługi zapisanej w protokole przewodowym, więc serwer ma nie ma możliwości sprawdzenia, czy klient otworzył plik O_APPEND.
Charles Duffy,
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.