Zapisałem następujący program w new.c
int main()
{
a;
return 0;
}
Zwraca komunikat o błędzie. Chcę wysłać tę wiadomość do pliku. Więc użyłem następującego polecenia
gcc new.c > temp.txt
Ale wciąż otrzymywałem dane wyjściowe na terminalu. Używam Ubuntu 13.04. Jak mogę to zrobić?
Odpowiedzi:
Kiedy kompilujesz program
gcc
, istnieją różne rodzaje danych wyjściowych: dostdout
istderr
. Zwykle>
przekierujestdout
strumień do pliku (na przykład wynik aprintf("hello world\n");
zostanie wysłany dostdout
). Jednakstderr
nadal jest wysyłany na ekran, ponieważ zakłada się, że jest to „coś wyjątkowego, o czym trzeba powiedzieć”.Istnieje sposób przekierowania stderr do pliku - robisz to za pomocą następującego (niezbyt intuicyjnego) polecenia:
gdzie
&>
jest „bash shorthand” dla „przekieruj wszystko”. Jak zauważył @CharlesDuffy, forma zgodna z POSIX toOznacza to „skompiluj 'new.c' i wyślij
stdout
domyFile
. I wyślijstderr
(2) w to samo miejsce costdout
(&1
=" to samo miejsce co standardowe wyjście ").Więcej informacji na temat różnych przekierowań znajdziesz na stronie http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-3.html i http://mywiki.wooledge.org/BashFAQ/055
Nawiasem mówiąc, jeśli chcesz wysłać coś bezpośrednio z programu
stderr
, możesz to zrobić w następujący sposóbJeśli umieścisz to w programie, uruchom program i wyślij „normalne” wyjście do pliku, nadal będzie ono widoczne na konsoli. Jeśli więc skompilujesz powyższe w pliku wykonywalnym
urgent
, wpiszna konsoli twoje wyjście pojawi się na ekranie.
źródło
>myFile 2>&1
) zgodny z POSIX, a także rozszerzenie bash (&>
).Ponieważ
>
przekierowuje tylko standardowe wyjście i zapisywane są błędystderr
, należy zamiast tego użyć jednego z poniższych:...lub...
&>
jest rozszerzeniem BASH, które przekierowuje zarówno plik, jakstdout
istderr
plik; inaczej, najprostszym rozwiązaniem jest pierwszym stdout przekierowania (>temp.txt
), a następnie dokonać stderr (FD 2) kopię już zostało przekształcone uchwytu pliku na standardowe wyjście (FD 1), tak:2>&1
.źródło
Jak powiedzieli inni, linux zapewnia dwa różne strumienie wyjściowe:
standardowe wyjście , czyli „standardowe wyjście”, jest tym, do czego trafiają wszystkie zwykłe wyjścia.
Możesz odwoływać się do niego za pomocą deskryptora pliku
1
.stderr lub „błąd standardowy” to osobny strumień dla informacji poza pasmem.
Możesz odwoływać się do niego za pomocą deskryptora pliku
2
.Dlaczego dwa różne strumienie wyjściowe? Rozważ szereg wymyślonych poleceń:
Teraz wyobraź sobie, że
decrypt
polecenie kończy się niepowodzeniem i generuje komunikat o błędzie. Gdyby wysłał tę wiadomośćstdout
, wysłałby ją do potoku, a gdyby nie miał słowa „sekret”, nigdy by go nie zobaczył. W rezultacie otrzymałeś pusty plik wyjściowy, nie mając pojęcia, co poszło nie tak.Ponieważ jednak rura tylko przechwytuje
stdout
,decrypt
polecenie może wysłać swoje błędy dostderr
, gdzie zostaną wyświetlone na konsoli.Możesz przekierować
stdout
istderr
razem lub osobno:Możesz przekierować błędy
stdout
i przetworzyć je tak, jakby były normalnym wyjściem:Można również użyć „skrótowej” notacji przekierować zarówno stdout i stderr do tego samego pliku:
I na koniec
>
operator najpierw obetnie swój plik wyjściowy przed zapisaniem do niego. Jeśli zamiast tego chcesz dołączyć dane do istniejącego pliku, użyj>>
operatora:źródło
$FOO
) jest częstym źródłem błędów, a pokazanie tego w przykładach nie jest takie świetne. (2) Używanie nazw zmiennych pisanych wielkimi literami jest głównym powodem konfliktów przestrzeni nazw między zmiennymi środowiskowymi a zmiennymi wbudowanymi (wielkie litery według konwencji) i zmiennymi lokalnymi (małe litery według konwencji). (3) Zachęcanie ludzi do wielokrotnego używania>>
(co powoduje ponowne otwieranie pliku za każdym razem, gdy jest on używany w poleceniu) zamiast otwierania pliku raz i pozostawianie deskryptora pliku otwartego do użycia przez wiele poleceń powoduje nieefektywny kod.exec 4>secrets; echo "this is a secret" >&4; echo "this is another secret" >&4
exec
z uproszczenia, chociaż w praktyce jest to ogólnie lepsza strategia.command₁
>
output_file
;
command₂
>>
the_same_output_file
(
command₁
;
command₂
) >
output_file
{
command₁
;
command₂
; } >
output_file
{
;
}