wyświetlać STDOUT przed STDERR?

9

Jestem nowy w bash i nie mogę przez całe życie wymyślić, jak uruchomić określone polecenie, przypuszczać ./fffi drukować standardowe stdouts przed stderr (sam jestem zdezorientowany co do znaczenia)

na przykład

$ printf "I am a\ndrill\n" > fff; 
$ cat fff nofile fff nofile fff

I am a
drill
cat: nofile: No such file or directory
I am a
drill
cat: nofile: No such file or directory
I am a
drill

musi drukować jak:

I am a
drill
I am a
drill
I am a
drill
cat: nofile: No such file or directory
cat: nofile: No such file or directory

Rozumiem, że najpierw muszę przekierować dane wyjściowe do pliku, a następnie dołączyć błąd do tego samego pliku, jednak takie dane wyjściowe otrzymuję

$ cat ./foo nofile ./foo nofile ./foo <<< $(touch fin) > see 2>> see 

I am a
drill
I am a
drill
I am a
drill
ectory
cat: nofile: No such file or directory
Miauczeć
źródło
2
Czy catnaprawdę „a” zastąpiono „niektórymi”?
Dmitrij Grigoriew
o Boże, mogłem zepsuć sznurek. Zaraz go edytuję @DmitryGrigoryev
MeOw

Odpowiedzi:

18

W każdym razie musisz gdzieś przechowywać wyjście stderr, aby móc wyświetlić go na końcu.

Plik przychodzi do głowy:

fff 2> file; cat file >&2

Lub pamięć (tutaj przy użyciu spongez moreutils):

{ fff 2>&1 >&3 3>&- | sponge >&2 3>&-; } 3>&1
  • {...} 3>&1: w obrębie {...}deskryptora pliku (fd) 3 wskazuje na ten sam zasób, co oryginalny stdout (więc możemy go użyć do przywrócenia standardowego wejścia fff).
  • fff <redirs> | sponge <redirs>, fffi spongezaczął jednocześnie (z <redirs>zastosowanym niezależnie) ze standardowym fffwyjściem do potoku, a spongestandardowym wyjściem jest drugi koniec potoku.
  • 2>&1: fd 2 z fff(stderr) wskazuje na to samo, co na 1: potok w tym punkcie, więc fffbłąd przechodzi spongeprzez tę potok.
  • >&3: teraz stdout wskazuje na pierwotne stdout (przekierowuje z powrotem do tego, co było)
  • 3>&-: zamykamy fd 2, który fffnie potrzebuje
  • spongegromadzi swoje dane wejściowe i wyświetla je tylko (na swoim standardzie, który został przekierowany >&2do tego samego zasobu co stderr) po wykryciu eof na swoim standardzie (zakłada się, że jest on fffzakończony i zapisał już wszystkie swoje wyjścia na standardowym standardzie ).

Jeśli spongenie jest zainstalowany, możesz go zastąpić perl -0777 -pe ''. Dzięki -pe '', perlbrzmi jeden rekord w czasie od jej wejścia i zapisuje je na standardowe wyjście. -0777jest trybem slurp, w którym (tylko w tym przypadku) rekord jest całym wejściem.

Stéphane Chazelas
źródło
Proszę, podziel się, jeśli masz czas!
George Udosen
Czy możemy użyć teezamiast sponge...?
George Vasiliou
@GeorgeUdosen zobacz edycję.
Stéphane Chazelas
1
@GeorgeVasiliou, teenie przechowuje danych, zapisuje je natychmiast po ich odczytaniu.
Stéphane Chazelas
2
@MeOw: W porządku, ale jak pokazuje trzecia linia odpowiedzi Stéphane'a, nie musisz ratować standardowego; po prostu zrób cat foo nofile foo nofile foo 2> ferr.txt; cat ferr.txt. (I prawdopodobnie nie chcesz używać >>.) Ponadto Stéphane podkreśla, że ​​powinieneś prawdopodobnie cat ferr.txt >&2napisać informacje o stderr do stderr.
G-Man mówi „Przywróć Monikę”