Rozważ ten skrypt:
tmpfile=$(mktemp)
cat <<EOS > "$tmpfile"
line 1
line 2
line 3
EOS
cat <(tail -1 "$tmpfile") "$tmpfile"
To działa i daje:
line 3
line 1
line 2
line 3
Powiedzmy, że nasze źródło danych wejściowych, zamiast być faktycznym plikiem, było zamiast tego standardowe:
cat <<EOS | # what goes here now?
line 1
line 2
line 3
EOS
Jak zmodyfikujemy polecenie:
cat <(tail -1 "$tmpfile") "$tmpfile"
Czy nadal wytwarza ten sam wynik w tym innym kontekście?
UWAGA: Konkretny Heredoc, którego łowię, a także użycie samego Heredoc, jest jedynie ilustracyjne. Każda akceptowalna odpowiedź powinna zakładać, że odbiera ona dowolne dane za pośrednictwem standardowego wejścia .
Odpowiedzi:
Próbować:
Przykład
Zdefiniuj zmienną za pomocą naszych danych wejściowych:
Uruchom nasze polecenie:
Ewentualnie moglibyśmy użyć tutaj dokumentu:
Jak to działa
x=x $0 ORS
To dołącza każdy wiersz danych wejściowych do zmiennej
x
.W awk
ORS
jest separatorem rekordów wyjściowych . Domyślnie jest to znak nowej linii.END{printf "%s", $0 ORS x}
Po czytaliśmy w całym pliku, Drukuje ostatnim wierszu
$0
, po czym zawartość całego plikux
.Ponieważ odczytuje to całe wejście do pamięci, nie byłoby właściwe dla dużych ( np. Gigabajtów) wejść.
źródło
tee
, ale jeśli stdin i plik, będziemy przesyłać ten sam stdin do dwóch różnych podstawień procesu. czy coś, co byłoby mniej więcej równoważne z tym?Jeśli stdin wskazuje na możliwy do przeglądania plik (jak w przypadku dokumentów bash (ale nie wszystkich innych powłok) tutaj, które są zaimplementowane z plikami tymczasowymi, możesz pobrać ogon, a następnie wyszukać ponownie przed odczytaniem pełnej zawartości:
Operatory wyszukiwania są dostępne w powłokach
zsh
lubksh93
, lub w językach skryptowych takich jak tcl / perl / python, ale nie wbash
. Ale zawsze możesz zadzwonić do bardziej zaawansowanych tłumaczy,bash
jeśli musisz z nich skorzystaćbash
.Lub
To nie zadziała, gdy stdin wskazuje na niewidoczne pliki, takie jak potok lub gniazdo. Następnie jedyną opcją jest odczyt i zapisanie (w pamięci lub w pliku tymczasowym ...) całego wejścia.
Podano już pewne rozwiązania dotyczące przechowywania w pamięci.
Za pomocą pliku tymczasowego
zsh
możesz:Jeśli w systemie Linux, z
bash
lubzsh
lub jakiejkolwiek powłoce że pliki zastosowania temp bo tu-dokumentów, można rzeczywiście wykorzystać plik tymczasowy utworzony przez tu-dokumentu, aby zapisać dane wyjściowe:źródło
Problem z przetłumaczeniem tego na coś, co używa,
tail
polega na tym, żetail
trzeba przeczytać cały plik, aby znaleźć jego koniec. Aby użyć tego w potoku, musisztail
.cat
.Problem polega na tym, aby nie powielać zawartości dokumentu (
tee
robi to), ale uzyskać wynik,tail
który ma się wydarzyć przed wydrukowaniem pozostałej części dokumentu, bez użycia pośredniego pliku tymczasowego.Używanie
sed
(lubawk
, jak John1024 ) eliminuje podwójne analizowanie danych i problem z porządkowaniem poprzez przechowywanie danych w pamięci.sed
Rozwiązania, które jest zaproponowanie1{h;d;}
, zapisz pierwszy wiersz w niezatrzymanym miejscu i przejdź do następnego.H
, dodajcie sobie nawzajem linię do miejsca wstrzymania za pomocą osadzonej nowej linii.${G;p;}
, dodaj przestrzeń wstrzymania do ostatniego wiersza z osadzoną nową linią i wydrukuj uzyskane dane.Jest to dosłowne tłumaczenie rozwiązania John1024 na
sed
, z zastrzeżeniem, że standard POSIX gwarantuje tylko, że przestrzeń wstrzymania wynosi co najmniej 8192 bajtów (8 KiB; ale zaleca, aby bufor ten był dynamicznie przydzielany i rozszerzany w razie potrzeby, które to oba GNUsed
i BSDsed
robi).Jeśli pozwolisz sobie na użycie nazwanego potoku:
Służy
tee
do wysyłania danych w dółmypipe
i jednocześnie docat
.cat
Narzędzie najpierw odczytać dane wyjściowetail
(który odczytuje zmypipe
, cotee
pisze się), a następnie dołączyć kopię dokumentu pochodzącego bezpośrednio ztee
.Jest w tym jednak poważna wada, polegająca na tym, że jeśli dokument jest zbyt duży (większy niż rozmiar bufora potoku),
tee
zapisujemypipe
icat
blokuje się podczas oczekiwania na opróżnienie (nienazwanego) potoku. Nie zostanie opróżniony, dopóki sięcat
z niego nie przeczyta.cat
nie czytałby z niego, dopóki siętail
nie skończy. Itail
nie skończy, dopóki siętee
nie skończy. Jest to klasyczny impas.Wariacja
ma ten sam problem.
źródło
sed
nie działa, jeśli wejście ma tylko jedną linię (być możesed '1h;1!H;$!d;G'
). Należy również pamiętać, że kilkased
implementacji ma niski limit rozmiaru wzoru i miejsca do przechowywania.W
pee
kolekcji narzędzi wiersza polecenia znajduje się narzędzie o nazwie „moreutils” (lub w inny sposób dostępne na stronie głównej ).Jeśli możesz mieć go w swoim systemie, odpowiednik dla twojego przykładu będzie wyglądał następująco:
Kolejność uruchamianych poleceń
pee
jest ważna, ponieważ są one wykonywane w podanej kolejności.źródło
Próbować:
Ponieważ cała rzecz to dosłowne dane („tutaj jest dokument”), a różnica między nim a pożądanym wynikiem jest banalna, po prostu masuj te dosłowne dane, aby dopasować wynik.
Załóżmy teraz, że
line 3
pochodzi skądś i jest przechowywany w zmiennej o nazwielastline
:W niniejszym dokumencie możemy wygenerować tekst, zastępując zmienne. Nie tylko to, ale możemy obliczyć tekst za pomocą podstawiania poleceń:
Możemy interpolować wiele linii:
Ogólnie rzecz biorąc, unikaj przetwarzania tekstu tutaj szablon doc; spróbuj wygenerować go za pomocą interpolowanego kodu.
źródło
cat <<EOS...
PO był tylko przykładem „catting a arbitrary file”, aby post był konkretny, a pytanie jasne. Czy to naprawdę nie było dla ciebie oczywiste, czy po prostu pomyślałeś, że sprytnie byłoby interpretować pytanie dosłownie?Jeśli nie zależy ci na zamówieniu. To zadziała
cat lines | tee >(tail -1)
. Jak powiedzieli inni. Musisz odczytać plik dwa razy lub buforować cały plik, aby zrobić to w żądanej kolejności.źródło