Dlaczego $ ls > ls.out
„ls.out” znajduje się na liście nazw plików w bieżącym katalogu? Dlaczego został wybrany? Dlaczego nie inaczej?
command-line
bash
redirect
Edward Torvalds
źródło
źródło
ls > ../ls.out
Odpowiedzi:
Podczas oceny polecenia
>
przekierowanie jest rozwiązywane w pierwszej kolejności: więc z biegiem czasuls
plik wyjściowy został już utworzony.Jest to również powód, dla którego odczyt i zapis do tego samego pliku przy użyciu
>
przekierowania w tym samym poleceniu obcina plik; do czasu uruchomienia polecenia plik został już obcięty:Sztuczki, aby tego uniknąć:
<<<"$(ls)" > ls.out
(działa dla każdego polecenia, które musi zostać uruchomione przed rozwiązaniem problemu z przekierowaniem)Podstawienie polecenia jest uruchamiane przed oceną polecenia zewnętrznego, więc
ls
jest uruchamiane przedls.out
utworzeniem:ls | sponge ls.out
(działa dla każdego polecenia, które musi zostać uruchomione przed rozwiązaniem problemu z przekierowaniem)sponge
zapisuje do pliku dopiero po zakończeniu wykonywania reszty potoku, więcls
jest uruchamiany przedls.out
utworzeniem (sponge
jest dostarczany zmoreutils
pakietem):ls * > ls.out
(działa wls > ls.out
konkretnym przypadku)Rozwinięcie nazwy pliku jest wykonywane przed rozstrzygnięciem przekierowania, więc
ls
będzie działać na jego argumentach, które nie będą zawieraćls.out
:Dlaczego przekierowania są rozwiązywane przed uruchomieniem programu / skryptu / czegokolwiek, nie widzę konkretnego powodu, dla którego jest to obowiązkowe , ale widzę dwa powody, dla których lepiej to zrobić:
nie przekierowanie STDIN wcześniej spowoduje zatrzymanie programu / skryptu / czegokolwiek, dopóki STDIN nie zostanie przekierowany;
brak wcześniejszego przekierowania STDOUT powinien koniecznie spowodować, że powłoka buforuje wyjście programu / skryptu / cokolwiek, dopóki STDOUT nie zostanie przekierowany;
Więc strata czasu w pierwszym przypadku i strata czasu i pamięci w drugim przypadku.
Właśnie to mi się przydarza. Nie twierdzę, że to są prawdziwe powody; ale wydaje mi się, że w sumie, gdyby ktoś miał wybór, i tak przekierowaliby go wcześniej z wyżej wymienionych powodów.
źródło
Od
man bash
:Pierwsze zdanie sugeruje, że dane wyjściowe są wysyłane w miejsce inne niż
stdin
przekierowanie tuż przed wykonaniem polecenia. Dlatego, aby zostać przekierowanym do pliku, plik musi najpierw zostać utworzony przez samą powłokę.Aby uniknąć posiadania pliku, sugeruję przekierowanie wyjścia do nazwanego potoku, a następnie do pliku. Zwróć uwagę na użycie,
&
aby zwrócić użytkownikowi kontrolę nad terminalemAle dlaczego?
Pomyśl o tym - gdzie będzie wynik? Program posiada funkcje takie jak
printf
,sprintf
,puts
, które domyślnie idź dostdout
, ale może ich być już do wyjścia pliku, jeśli plik nie istnieje w pierwszej kolejności? To jest jak woda. Czy możesz dostać szklankę wody, nie wkładając najpierw szklanki pod kran?źródło
Nie zgadzam się z obecnymi odpowiedziami. Plik wyjściowy musi zostać otwarty przed uruchomieniem polecenia, w przeciwnym razie polecenie nie będzie miało miejsca na zapisanie danych wyjściowych.
Wynika to z faktu, że „wszystko jest plikiem” w naszym świecie. Wyjście na ekran to SDOUT (inaczej deskryptor pliku 1). Aby aplikacja mogła pisać na terminalu, otwiera fd1 i zapisuje w nim jak plik.
Kiedy przekierowujesz dane wyjściowe aplikacji w powłoce, zmieniasz fd1, tak aby wskazywał na plik. Podczas potoku zmieniasz STDOUT jednej aplikacji, aby stał się STDIN innej aplikacji (fd0).
Ale miło jest to powiedzieć, ale możesz dość łatwo sprawdzić, jak to działa
strace
. To dość ciężkie rzeczy, ale ten przykład jest dość krótki.Wewnątrz
strace.out
możemy zobaczyć następujące najważniejsze informacje:To otwiera się
ls.out
jakofd3
. Tylko pisać. Obcina (zastępuje), jeśli istnieje, w przeciwnym razie tworzy.To trochę żonglerka. Przesuwamy STDOUT (fd1) do fd10 i zamykamy go. Wynika to z faktu, że za pomocą tego polecenia nie wypisujemy niczego na prawdziwy STDOUT. Kończy się poprzez skopiowanie dojścia do zapisu
ls.out
i zamknięcie oryginalnego.To jest szukanie pliku wykonywalnego. Lekcja może nie mieć długiej ścieżki;)
Następnie polecenie jest uruchamiane i rodzic czeka. Podczas tej operacji dowolne STDOUT zostanie faktycznie zamapowane na uchwyt otwartego pliku
ls.out
. Gdy dziecko podaSIGCHLD
problem, informuje to, że proces nadrzędny jest zakończony i że może wznowić. Kończy się trochę żonglowaniem i zakończeniemls.out
.Dlaczego istnieje tak wiele żonglerka? Nie, nie jestem też do końca pewien.
Oczywiście możesz zmienić to zachowanie. Możesz buforować do pamięci z czymś podobnym,
sponge
a to będzie niewidoczne z polecenia. Nadal wpływamy na deskryptory plików, ale nie w sposób widoczny dla systemu plików.źródło
Jest też fajny artykuł na temat implementacji przekierowań i operatorów potoków w powłoce . Co pokazuje, jak można zastosować przekierowanie, aby
$ ls > ls.out
mogło wyglądać:źródło