Czy Zsh może uzyskać dostęp do standardowego wyjścia ostatniego programu?

16

Często używam findlub, locateaby dowiedzieć się o ścieżkach.

(~) locate foobar.mmpz
/home/progo/lmms/projects/foobar.mmpz

Następnym krokiem jest często otwieranie plików lub manipulowanie nimi w inny sposób. W szczęśliwym przypadku, takim jak powyżej, mogę to zrobić:

(~) ls `!!`
ls `locate foobar.mmpz`
/home/progo/lmms/projects/foobar.mmpz

Ale nikt nie jest zbyt szczęśliwy, gdy istnieje wiele linii wyników, z których niektóre mogą nie być ścieżkami lub czymś innym. Poza tym ponowne uruchamianie potencjalnie marnotrawnych poleceń również nie jest tak eleganckie.

Czy byłby sposób na podłączenie zsh do przechowywania standardowego wejścia w tablicy do późniejszej manipulacji? W końcu zadaniem powłoki jest przekierowanie strumieni do użytkownika. Myślę, że może przechowywać pierwszą N i ostatnią N linii w zmiennej do natychmiastowego późniejszego użycia, jak $?i innych.

Ok, więc to całkiem fajne: /unix//a/59704/5674 . Pytam teraz o know-how zsh (i przenoszenie kodu do zsh), aby ustawić ten rodzaj przechwytywania po każdej linii uruchamiania.

unperson325680
źródło
Przekierowanie strumienia do użytkownika nie jest zadaniem powłoki. Aplikacje zapisują swoje dane wyjściowe na urządzeniu końcowym, powłoka nie bierze w tym udziału.
Stéphane Chazelas
@StephaneChazelas, ale zadaniem powłoki jest, powiedzmy, przekierowywanie strumieni do plików na żądanie użytkownika. Istnieją również przepisy na Zsh, które kolorują stderr na czerwono, aby oddzielić go od standardowego wyjścia. Myślę, że to wskazuje na rolę powłoki w sprawach przesyłania strumieniowego.
unperson325680
Tak, możesz to zrobić za pomocą haków screenlub scripti precmd i preexec.
Stéphane Chazelas

Odpowiedzi:

7

W większości emulatorów terminali nie ma funkcji przechwytywania obrazu z ekranu. Wydaje mi się, że pamiętam autora xterm (emulator terminala „referencyjnego”), który stwierdził, że jego wdrożenie byłoby trudne. Nawet gdyby to było możliwe, pocisk musiałby śledzić, gdzie była ostatnia podpowiedź.

Dzięki temu nie unikniesz konieczności ponownego uruchomienia polecenia, chyba że użyjesz ręcznego mechanizmu specyficznego dla terminala, takiego jak wklejanie kopii za pomocą myszy w Xterm lub klawiatury w Screen.

Byłoby bardzo niepraktyczne, aby powłoka automatycznie przechwytywała dane wyjściowe poleceń, ponieważ nie może odróżnić poleceń, które mają złożone interakcje między terminalem a użytkownikiem, od poleceń, które po prostu wypisują znaki do wydruku.

Możesz ponownie uruchomić polecenie i przechwycić jego wynik. Istnieją różne sposoby wykonania każdego z nich. Aby ponownie uruchomić polecenie, możesz użyć:

  • !! podstawianie historii - najwygodniejszy do pisania;
  • fc -e -, którego można użyć w funkcji.

Aby przechwycić dane wyjściowe, można użyć podstawienia polecenia lub funkcji takiej jak poniżej:

K () {
  lines=("${(f@)$(cat)}")
}
!! |K

Spowoduje to ustawienie linestablicy na wynik polecenia, które jest do niej podłączone.

Gilles „SO- przestań być zły”
źródło
Niech tak będzie. Teraz, w świetle dobrych wyjaśnień, zdaję sobie sprawę, że całkowicie automatyczne podejście jest zbyt trudne, podobnie jak Ktwoje.
unperson325680
3

Oto pierwsze cięcie czegoś, aby umieścić ostatni wiersz wyniku w zmiennej o nazwie $lastline.

precmd () {                                                                                                                                                                                                        
    exec 2>&- >&-
    lastline=$(tail -1 ~/.command.out) 
    sleep 0.1   # TODO: synchronize better
    exec > /dev/tty 2>&1
}

preexec() {
    exec > >(tee ~/.command.out&)
}

Używa preexechaka zsh do uruchamiania execsię teedo przechowywania kopii standardowego polecenia, a następnie używaprecmd do odczytu zapisanej wyjście i przywrócić stdout być tylko terminal do wyświetlania monitu.

Ale wciąż potrzebuje trochę pracy. Na przykład, ponieważ stdout nie jest już terminalem, programy takie jak vimi lessnie działają poprawnie.

W tych pytaniach znajduje się kilka przydatnych informacji pokrewnych:

Mikel
źródło
Tak, być może 100% automatyczne podejście nie zadziała. W execkodzie jest wiele wywołań, czy polecenie jest uruchamiane wiele razy, czy też jestem przyłapany na specjalnej semantyce?
unperson325680
execbez nazwy programu po prostu ustawia przekierowania.
Mikel
2

Możesz to zrobić po prostu teeprzesyłając wyniki do , co zapisuje dane wyjściowe w pliku i wyświetla je jednocześnie.

Na przykład możesz to zrobić, co pokazuje normalne wyniki, ale także zapisuje je w pliku /tmp/it

locate foobar.mmpz | tee /tmp/it

następnie cat ten plik i grep go, aby wybrać rzeczy, np

cat /tmp/it | grep progo | grep lms

aby go użyć, możesz po prostu to zrobić:

vi $(!!)

Brad Parks
źródło
2

Wymyśliłem to na wpół upieczone rozwiązanie:

alias -g ___='"$(eval "$(fc -ln -1)" | tail -n 1)"'

To pozwala pisać ___w dowolnym punkcie wiersza poleceń. Poprzednie polecenie zostanie ponownie uruchomione i ___zostanie zastąpione ostatnim wierszem danych wyjściowych. Przykładowe użycie:

$ touch foo bar baz
$ ls -1
bar
baz
foo
$ vim ___

Ostatnie polecenie zostanie rozwinięte do vim foo.

Ma to pewne ostre krawędzie!

  • Jeśli włączysz ___polecenie, ale poprzednie polecenie zawierało również a ___, powłoka przez pewien czas zawiesi się w dziwnym stanie. Możesz natychmiast wyjść z tego stanu za pomocą Ctrl- C.

  • Nie możesz także nacisnąć, Tababy rozwinąć ___, podobnie jak w przypadku !$innych konstrukcji.

  • Niektóre polecenia wyświetlają inne dane wyjściowe, gdy są uruchamiane „normalnie” i gdy są podłączone do potoku. (Porównaj dane wyjściowe z lsi ls | cat.) Jeśli polecenie uruchomione przez ___jest jednym z nich, możesz w końcu uruchomić inne polecenie, niż się spodziewałeś.

  • I oczywiście, jeśli chcesz zrobić coś z linią wyjściową inną niż ostatnia, to ci nie pomoże.

Wybrałem tę nazwę, ___ponieważ nigdy nie chciałem jej podawać jako słowa w wierszu poleceń, nawet jako argumentu. Możesz wybrać inną nazwę, ale uważaj, aby nie wybrać czegoś, co może zostać przypadkowo rozszerzone.

bdesham
źródło