za jakiś czas zrób coś (a może pokaż też wynik w konsoli)


12

Korzystam z serwera Ubuntu 16.04 i chcę użyć narzędzia atw mojej bieżącej sesji, aby zrobić coś za 1 minutę (powiedzmy, an echo), bez podawania konkretnej daty i godziny - zaledwie 1 minutę do przodu od aktualnego czasu.

To się nie udało:

echo 'hi' | at 1m

Powodem wybiorę atnad sleepdlatego handicapy snu bieżącej sesji i jest dla nich bardziej nadaje się do poleceń opóźnienia w innej sesji, zamiast pracy z jednych my przez większość czasu. AFAIR, atnie zachowuje się w ten sposób i nie utrudnia mojej sesji.

Aktualizacja_1

Według odpowiedzi Pied Piper próbowałem:

(sleep 1m; echo 'hi')  &

Mam problem z tą metodą: strumień „cześć” jest drukowany wewnątrz mojego głównego monitu, a także dodaje pusty dodatkowy monit ( _) bezpośrednio pod głównym monitem, który go zawiera, patrz:

USER@:~# (sleep 1m; echo 'hi')  &
[1] 22731
USER@:~# hi
^C
[1]+  Done

Aktualizacja_2

Na odpowiedź Petera Corde'a próbowałem:

(sleep 2 && echo -e '\nhi' && kill -WINCH $$ &)

Działa to poprawnie w Bash 4.4, ale najwyraźniej nie w niektórych starszych wersjach (patrz komentarze w odpowiedzi). Osobiście korzystam z Bash 4.3 we własnym środowisku.


2
Chciałbym, aby flagi zabicia były w stylu GNU i mogły zostać zmienione, aby nie brzmiało to jak „zabij dziewkę”!
NH.

Odpowiedzi:


6

Strumień „cześć” jest drukowany w moim monicie (w stdin), a nie w moimstdout

Nie, nie jest to „wydrukowane na twoim stdin”.

Jeśli naciśniesz klawisz Return, nie będzie próbował uruchomić się hijako polecenie. Tyle tylko, że tło echodrukowane było, higdy kursor znajdował się za twoim monitem.


Być może chcesz wydrukować wiodący nowy wiersz , na przykład (sleep 1m && echo -e '\nhi' &). (Dostosuj odpowiednio do echopowłoki. Lub użyj printfdla przenośności.)

Umieszczam &wnętrze podpowłoki, aby „wyłączyć” zadanie w tle, abyś także unikał „szumu” [1]+ Done. Z &&pomiędzy poleceniami, &odnosi się do całego łańcucha związek-polecenia, więc wraca do powłoki wiersza od razu, zamiast czekać na sleepdo wyjścia jak dałaby(sleep 1; echo ... &)

Oto, co się stanie (z 1-sekundowym opóźnieniem):

peter@volta:~$ (sleep 1 && echo -e '\nhi' &)
peter@volta:~$ 
hi
       # cursor is at the start of this empty line.

Bash nie wie, że echocoś wydrukował, więc nie wie, że musi ponownie wydrukować monit lub wyczyścić ekran. Możesz to zrobić ręcznie za pomocą control-L.

Możesz napisać funkcję powłoki, która pobiera bash, aby ponownie wydrukować monit po echozakończeniu . Samo działanie echo "$PS1"nie odtworzy już wpisanych znaków. kill -WINCH $$w moim systemie pojawia się bash, aby ponownie wydrukować wiersz zachęty bez czyszczenia ekranu, pozostawiając hiwiersz sam przed monitem. SIGWINCH jest wysyłany automatycznie, gdy zmienia się rozmiar okna WINDow, a reakcja bash na to dzieje się tak, jak chcemy.

Może działać z innymi powłokami, ale nie próbuję uczynić tego w 100% przenośnym / POSIX. ( Niestety działa to tylko na bash4.4, nie na bash4.3 lub zależy od niektórych ustawień, których nie znam )

  # bash4.4
peter@volta:~$ (sleep 2 && echo -e '\nhi' && kill -WINCH $$ &)
peter@volta:~$ ljlksjksajflasdf dfas      # typed in 2 seconds
hi
peter@volta:~$ ljlksjksajflasdf dfas      # reprinted by Bash because of `kill -WINCH`

Można to łatwo zawinąć w funkcję powłoki, która pobiera argument uśpienia i komunikat.

bash 4.3 nie drukuje ponownie swojego monitu po SIGWINCH, więc to nie działa. Mam shopt -s checkwinsizewłączone na obu systemach, ale działa tylko w systemie Bash 4.4 (Arch Linux).

Jeśli to nie działa, możesz spróbować (sleep 2 && echo -e '\nhi' && echo "$PS1" &), który „działa”, jeśli wiersz poleceń jest pusty. (Ignoruje również ustawioną możliwość PROMPT_COMMAND).


Nie ma naprawdę czystego sposobu na zmiksowanie wyjścia terminala z tym, co możesz zrobić na swoim terminalu później, gdy zadziała timer. Jeśli jesteś w trakcie przewijania czegoś less, możesz łatwo tego przegapić.

Jeśli szukasz czegoś z interaktywnymi wynikami, sugeruję odtworzenie pliku audio. np. z odtwarzaczem wiersza poleceń, takim jak mpv(fajny fork MPlayera2). Lub wybierz plik wideo, aby otworzyć nowe okno.

(sleep 1 && mpv /f/share/music/.../foo.ogg </dev/null &>/dev/null &)

Możesz chcieć echootworzyć swój nowy xterm / konsole / gnome-terminal. Użyj opcji, która utrzymuje terminal otwarty po wyjściu polecenia.


Bardzo ci dziękuję, David, i podniosłem głowę. To naprawdę najbliższe, jeśli chodzi o to, czego szukam. Czy istnieje sposób na uaktualnienie następującego polecenia, aby emulować Enterzdarzenie naciśnięcia klawisza, zaraz po pojawieniu się echa, aby automatycznie wrócić do głównego monitu konsoli ? (sleep 2 && echo -e '\nhi' && kill -WINCH $$ &).
Arcticooling,

@Arcticooling: kill -WINCH $$ nie odświeżać zachęty powłoki uruchomiony w terminalu. Właśnie o to chodziło. Naciśnięcie Enter spowoduje przesłanie częściowo wpisanego polecenia, ale WINCH nie, jak pokazałem. Jeśli nic nie wpisałeś, pojawia się pusty monit.
Peter Cordes,

1
Jeśli zaczniesz pisać rm -rf ~/some/directory, Enter w niewłaściwym czasie może się uruchomić rm -rf ~/. (Wskazówka bezpieczeństwa: zakończ pisanie ścieżek, a następnie naciśnij klawisz Control-a i zmień lsna rm -rf, aby tłuste palce Enter w każdej chwili nie zrujnowały twojego dnia.)
Peter Cordes

Przewodowe, wykonałem (sleep 2 && echo -e '\nhi' && kill -WINCH $$ &)i po pojawieniu się echa dostałem pusty monit, dopiero po trafieniu Enterwróciłem do głównego ... Przepraszam, jeśli cię źle zrozumiem, jestem całkiem nowy w Bash.
Arcticooling,

@Arcticooling: Używam Bash 4.4 na Arch Linux, w emulatorze terminali Konsole. Miałem nadzieję, że moje polecenie będzie przenośne przynajmniej dla innych wersji bash, ale może nie :( Tak, właśnie przetestowałem w Bash 4.3 w screensesji (i tylko przez SSH) na starszym systemie Ubuntu, i dostałem zachowanie, które opisujesz.
Peter Cordes,

13

Prawidłowe w użyciu jest at <timespec>, gdzie <timespec>jest specyfikacja czasu. Możesz również użyć tej -fopcji, aby określić plik zawierający polecenia do wykonania. Jeśli -fi nie jest używane przekierowanie, at przeczyta polecenia do wykonania ze standardowego wejścia (standardowe wejście).

W twoim przykładzie, aby wykonać „jakieś polecenie” (wybrałem „jakieś polecenie”, aby być „echo cześć” w poniższym przykładzie) minutę po naciśnięciu klawisza enter (teraz), <timespec>należy użyć now + 1 minute. Tak więc, aby uzyskać pożądany wynik za pomocą rozwiązania jednowarstwowego, użyj poniższego polecenia:

echo 'echo hi' | at now + 1 minute

Ma to (i zrobi) uruchomienie echo hipolecenia po minucie. Problem polega na tym, że echo hipolecenie zostanie wykonane przez polecenie at w atrapie tty, a dane wyjściowe zostaną wysłane do skrzynki pocztowej użytkownika (jeśli jest poprawnie skonfigurowana - co wymaga bardziej szczegółowego wyjaśnienia, jak skonfigurować skrzynkę pocztową w maszyna uniksowa i nie jest objęta zakresem tego pytania). Najważniejsze jest to, że nie będziesz mógł bezpośrednio zobaczyć wyniku echo hiw tym samym terminalu, z którego wydałeś polecenie. Najłatwiejszą alternatywą jest przekierowanie go do „jakiegoś pliku”, na przykład:

echo 'echo hi > /tmp/at.out' | at now + 1 minute

W powyższym przykładzie „jakiś plik” jest, /tmp/at.outa oczekiwanym rezultatem jest to, że plik at.outw / tmp jest tworzony po minucie i zawiera tekst „cześć”.

Oprócz now + 1 minutepowyższego przykładu, można zastosować wiele innych specyfikacji czasu, nawet niektóre złożone. Polecenie at jest wystarczająco inteligentne, aby interpretować te całkiem czytelne dla ludzi, takie jak poniższe przykłady:

now + 1 day, 13:25, mid‐night, noon, ...

Więcej informacji na temat możliwych specyfikacji czasu można znaleźć na stronie podręcznika użytkownika at, ponieważ możliwe odmiany są dość obszerne i mogą obejmować daty, czasy względne lub bezwzględne itp.


2
atdomyślnie wysyła dane wyjściowe pocztą, ale musi to być odpowiednio skonfigurowane do działania.
Simon Richter,

Teraz oferuję nagrodę w wysokości 100 powtórzeń za odpowiedź. Proszę przeczytać moją wiadomość o nagrodę poniżej i edytować, aby wyjaśnić więcej na temat tego, co jest at <timespec>i flagi, której użyłeś i czy pasuje do Xenial Ubuntu 16.04.
Arcticooling,

Ok, podniosłem poziom szczegółowości w odpowiedzi, dzięki czemu jest teraz bardziej dydaktyczny. Dla niektórych może się to wydawać nieco rozwlekłe, ale uważam, że nie pozostawia to żadnych wątpliwości, ponieważ wyraźnie przytacza przykłady, które działają i jak działają.
Marcelo,

7

Uruchom sleepw podpowłoce:

(sleep 60; echo -e '\nhi')  &

Uwaga: w systemie Linux argument można spać w ciągu kilku sekund lub z przyrostkiem s / m / h / d (dla sekund, minut, godzin, dni). Na BSD argument musi być podany w sekundach


Mam niewielki problem z tą metodą - strumień „cześć” jest drukowany w moim monicie (w stdin), a nie w moim stdout(jak w przypadku zwykłego echo).
Arcticooling,

1
Jeśli nie chcesz, aby dane wyjściowe w twoim terminalu były pomieszane z monitami i danymi wyjściowymi innych poleceń, musisz je gdzieś przekierować
PiedPiper

To przekierowanie nie powiodło się @PiedPiper (sleep 10s; echo 'hi') & 1>. Teraz czytam więcej na ten temat.
Arcticooling,

2
Czytanie dokumentacji jest zawsze dobrym pomysłem :)
PiedPiper

1
@Arcticooling Wygląda na to, że masz wątpliwości co do znaczenia stdini stdout. Nie mają one nic wspólnego z tym, gdzie rzeczy pojawiają się na twoim terminalu; zamiast tego powinieneś interpretować je w odniesieniu do konkretnego procesu (w zasadzie programu). Standardowe dane wejściowe („standardowe wejście”) dla procesu to źródło, z którego proces może odczytywać dane, a standardowe dane wyjściowe procesu („standardowe wyjście”) to miejsce docelowe, do którego może zapisywać dane. Tymi źródłami i miejscami docelowymi mogą być inne programy, pliki lub sam terminal (wpisywane przez ciebie pliki idą do standardowego wejścia i wyświetlane jest wszystko, co przychodzi do standardowego wyjścia).
David Z

3

Że nie powiodło się, ponieważ jesteś potokiem wyjście echo "hi", które jest tylko hido at, ale atspodziewa się, że jest to wejście może być wykonywane przez powłokę domyślnym systemowym (zwykle bash, ale czasami coś innego w zależności od systemu).

To:

at 1m << EOF
echo "hi"
EOF

osiągnie to, co próbujesz zrobić. Wykorzystuje konstrukcję powłoki zwaną „dokumentem tutaj”, co jest ogólnie przyjętym sposobem wykonywania tego typu czynności (ponieważ obsługuje wiele wierszy lepiej niż przy użyciu echopolecenia i nie wymaga tworzenia nowego pliku, tak jak trzeba to zrobić z cat) i przekłada się na nieco bardziej skomplikowany odpowiednik przy użyciu echo:

echo 'echo "hi"' | at 1m

Prawdopodobnie warto zauważyć, że atwyśle ​​wszelkie dane wyjściowe polecenia do użytkownika, który wywołał atpolecenie, zamiast łączyć dane wyjściowe z terminalem, tak jak sleepzrobiłoby to polecenie opóźnione w podpowłoce. W szczególności oznacza to, że dopóki nie dostosujesz systemu lub nie zamierzasz czytać lokalnego bufora poczty, nie będziesz w stanie uzyskać wyjścia poleceń at.


Z jakiegoś powodu oba podane przez ciebie przykłady dają mi błąd syntax error. Last token seen: m Garbled time . Nie mam pojęcia dlaczego. Używam Ubuntu 16.04, Bash 4.0. Może zrobiłeś to na innym systemie. Nawet gdy piszę atbez żadnych dalszych argumentów --- wciąż pojawia się ten sam błąd. Więcej danych tutaj .
Arcticooling,

1
at 1mnie działa dla kompatybilnego z POSIX-em at. Polecenie musiałoby byćat now + 1 minute
PiedPiper

@PiedPiper jest poprawny, 1m nie jest zgodny z wersjami zgodnymi z POSIX at, po prostu zakładałem, że masz wersję, która zaakceptowała tę składnię.
Austin Hemmelgarn,

@PiedPiper, at 1mnie jest POSIX- em, ale implementacje kompatybilne z POSIX- em atmogą dowolnie interpretować to, co chcą, nie czyni to atimplementacji mniej zgodną, ​​aby interpretować to tak samo, jak now + 1 minutezwracanie błędu lub znaczenia miesiąc temu . IOW, to at 1mkod, który nie jest POSIX.
Stéphane Chazelas,

2

Połącz odpowiedź @Peter Cordes i tę odpowiedź /programming/23125527/how-to-return-to-bash-prompt-after-printing-output-from-backgrounded-function/23125687#23125687

Poniższy kod pochodzi z drugiej odpowiedzi, z niewielką zmianą mojego. Skompiluj go do pliku a.out (dowolna nazwa)

#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
        char *tty = "/dev/tty";
        if (argc > 1)
                tty = argv[1];
        int fd = open(tty, O_WRONLY);

        int i;
        char buf[] = "\n";
        for (i = 0; i < sizeof buf - 1; i++)
                if (ioctl(fd, TIOCSTI, &buf[i]))
                        perror("ioctl");
        close(fd);
        return 0;
}

Następnie uruchom poniższe polecenie. (Umieściłem a.out w katalogu dir / tmp /, być może trzeba będzie zmienić na swój)

(sleep 2 && echo -e '\nhi' && /tmp/a.out &)

lub

(sleep 2 && echo -e '\nhi' && /tmp/a.out /proc/$$/fd/0 &)

BTW, kill -WINCH $$działa dobrze dla mnie z Bash 4.3 na Gentoo.


1

Opierając się na powyższych odpowiedziach, możesz osadzić polecenie skierowane do wyjścia na terminalu:

echo "echo hi >$(tty); kill -WINCH $$" | at now + 1 minute

ttyPolecenie zwraca ścieżkę urządzenie swojego obecnego terminalu, zamykając go w $(...)ma bash wykonać go w sub-shell, a polecenie kill wysyła sygnał do bieżącego procesu, który będzie miał bash ponownego wydrukowania szybka jego $ PS1.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.