a un certo punto da adesso fai qualcosa (e forse mostra anche i risultati nella console)


12

Uso Ubuntu server 16.04 e desidero utilizzare l'utilità atnella mia sessione corrente per fare qualcosa tra 1 minuto (diciamo, an echo), senza dare una data e un'ora specifiche - solo 1 minuto in anticipo rispetto all'ora corrente.

Questo non è riuscito:

echo 'hi' | at 1m

La ragione per cui ho scelto atsopra sleepè perché handicap sonno sessione corrente ed è Perciò più adatto ai comandi di ritardo in un'altra sessione, piuttosto che il lavoro che abbiamo con la maggior parte del tempo. AFAIR, atnon si comporta in questo modo e non ostacolerà la mia sessione.

Update_1

Con la risposta di Pied Piper, ho provato:

(sleep 1m; echo 'hi')  &

Ho un problema con questo metodo: il flusso "hi" viene stampato nel mio prompt principale e aggiunge anche un prompt secondario vuoto ( _) proprio sotto il prompt primario che lo contiene, vedere:

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

Update_2

Con la risposta di Peter Corde ho provato:

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

Funziona correttamente in Bash 4.4, ma non in alcune versioni precedenti, a quanto pare (vedi commenti nella risposta). Personalmente uso Bash 4.3 nei miei ambienti.


2
Vorrei che le kill flag fossero in stile GNU e potessero essere riorganizzate in modo da non sembrare "uccidi la donna"!
NH.

Risposte:


6

Il flusso "hi" viene stampato nel mio prompt (nel stdin) e non nel miostdout

No, non è "stampato nel tuo stdin".

Se si preme return, non proverà ad essere eseguito hicome comando. È solo che lo sfondo echostampato himentre il cursore era dopo il tuo prompt.


Forse vuoi stampare una nuova riga principale , come (sleep 1m && echo -e '\nhi' &). (Regola secondo necessità per la echotua shell. O usa printfper la portabilità.)

Ho messo l' &interno della sotto-shell per "rinnegare" il lavoro in background, in modo da evitare anche il "rumore" di [1]+ Done. Con &&tra i comandi, si &applica all'intera catena di comandi composti, quindi ritorna immediatamente al prompt della shell invece di aspettare sleepche esca come si otterrebbe(sleep 1; echo ... &)

Ecco cosa succede (con 1 secondo di ritardo):

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

Bash non sa che ha echostampato qualcosa, quindi non sa che deve ristampare il suo prompt o ripulire lo schermo. Puoi farlo manualmente con control-L.

È possibile scrivere una funzione shell che ottiene bash per ristampare il suo prompt al echotermine . Fare semplicemente echo "$PS1"non riprodurrà alcun personaggio già digitato. kill -WINCH $$sul mio sistema ottiene bash per ristampare la sua riga di prompt senza cancellare lo schermo, lasciando hisu una riga da sola prima del prompt. SIGWINCH viene inviato automaticamente quando la dimensione di WINdow cambia, e la risposta di bash accade per fare ciò che vogliamo.

Potrebbe funzionare con altre shell, ma non sto cercando di creare questo POSIX / portatile al 100%. ( Sfortunatamente, questo funziona solo su bash4.4, non bash4.3 o dipende da alcune impostazioni di cui non sono a conoscenza )

  # 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`

Potresti facilmente riassumerlo in una funzione shell che accetta un argomento sleep e un messaggio.

bash 4.3 non ristampa il suo prompt dopo SIGWINCH, quindi questo non funziona lì. Ho shopt -s checkwinsizeabilitato su entrambi i sistemi, ma funziona solo sul sistema Bash 4.4 (Arch Linux).

Se non funziona, puoi provare (sleep 2 && echo -e '\nhi' && echo "$PS1" &), che "funziona" se la riga di comando è vuota. (Ignora anche la possibilità che PROMPT_COMMANDè impostata.)


Non c'è un modo davvero pulito per far sì che l'output del terminale si mescoli con qualsiasi cosa tu possa fare sul tuo terminale in seguito, quando il timer scatta. Se sei nel mezzo dello scorrimento di qualcosa less, potresti facilmente perderlo.

Se stai cercando qualcosa con risultati interattivi, ti suggerisco di riprodurre un file audio. ad esempio con un giocatore a riga di comando come mpv(bel fork di MPlayer2). Oppure scegli un file video per aprire una nuova finestra.

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

Potresti voler echoaprire un nuovo terminale xterm / konsole / gnome. Utilizzare un'opzione che mantiene aperto il terminale dopo la chiusura del comando.


Ti ringrazio di cuore David, e ho sfogliato. Questo è davvero il più vicino che ho avuto riguardo a ciò che cerco. Esiste un modo per aggiornare il seguente comando in modo da emulare un Enterevento di pressione dei tasti, subito dopo la comparsa dell'eco, in modo da tornare automaticamente al prompt principale della console ? (sleep 2 && echo -e '\nhi' && kill -WINCH $$ &).
Arcticooling il

@Arcticooling: kill -WINCH $$ non aggiorna l'invito della shell in esecuzione nel terminale. Era questo il punto di usarlo. Premendo Invio si invia un comando parzialmente digitato, ma WINCH no, come ho mostrato. Se non hai digitato nulla, ricevi un messaggio vuoto.
Peter Cordes,

1
Se avessi iniziato a digitare rm -rf ~/some/directory, Invio potrebbe essere eseguito nel momento sbagliato rm -rf ~/. (Suggerimento per la sicurezza: finisci di digitare i percorsi e poi controlla-a e cambia lsin rm -rf, quindi entra in qualsiasi momento con la diteggiatura grassa non rovinerà la tua giornata.)
Peter Cordes

Cablato, l'ho eseguito (sleep 2 && echo -e '\nhi' && kill -WINCH $$ &)e dopo che l'eco è apparso ho ricevuto un messaggio vuoto, solo dopo Enteraverlo fatto sono tornato al messaggio principale ... Scusami se ti fraintendo, sono abbastanza nuovo con Bash.
Arcticooling il

@Arcticooling: sto usando Bash 4.4 su Arch Linux, in un emulatore di terminale Konsole. Speravo che il mio comando fosse portatile almeno ad altre versioni di bash, ma forse no :( Sì, appena testato in Bash 4.3 all'interno di una screensessione (e solo attraverso SSH) su un vecchio sistema Ubuntu, e ho ottenuto il comportamento che descrivi.
Peter Cordes,

13

Il corretto all'utilizzo è at <timespec>, dove <timespec>è la specifica del tempo. È inoltre possibile utilizzare l' -fopzione per specificare il file contenente i comandi da eseguire. Se -fnon viene utilizzato il reindirizzamento, at leggerà i comandi da eseguire dallo stdin (input standard).

Nel tuo esempio, per eseguire "alcuni comandi" (ho scelto "alcuni comandi" per essere "echo hi" nell'esempio seguente) un minuto dopo aver premuto Invio (ora), lo scopo <timespec>da utilizzare è now + 1 minute. Quindi, per ottenere il risultato desiderato con una soluzione a linea singola, utilizzare il comando seguente:

echo 'echo hi' | at now + 1 minute

Questo dovrebbe (e lo farà) eseguire il echo hicomando dopo un minuto. Il problema qui è che il echo hicomando verrà eseguito dal comando at in un fittizio tty e l'output verrà inviato alla casella di posta dell'utente (se è configurato correttamente - il che richiede una spiegazione più ampia su come configurare una casella di posta in una macchina unix e non fa parte dell'ambito di questa domanda). La linea di fondo è che non sarai in grado di vedere direttamente il risultato echo hinello stesso terminale in cui hai emesso il comando. L'alternativa più semplice è reindirizzarlo a "alcuni file", ad esempio:

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

Nell'esempio sopra, "alcuni file" è /tmp/at.oute il risultato atteso è che il file at.outin / tmp viene creato dopo un minuto e contenga il testo "ciao".

Oltre now + 1 minuteall'esempio sopra, è possibile utilizzare molte altre specifiche temporali, anche alcune complesse. Il comando at è abbastanza intelligente da interpretare quelli abbastanza leggibili come gli esempi seguenti:

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

Per ulteriori informazioni sulle possibili specifiche temporali, consultare la pagina man di at poiché le possibili variazioni sono piuttosto estese e possono includere date, tempi relativi o assoluti, ecc.


2
atper impostazione predefinita invia l'output via mail, ma deve essere configurato correttamente per funzionare.
Simon Richter,

Ora offro una ricompensa di 100 rappresentanti per una risposta. Si prega di leggere il mio messaggio di ricompensa qui sotto e modificarlo per spiegare di più su ciò che è at <timespec>e la bandiera che hai usato e se si adatta a Ubuntu 16.04 xenial.
Arcticooling,

Ok, ho aumentato il livello di dettaglio nella risposta in modo che ora sia più didattico. Può sembrare un po 'prolisso per alcuni, ma credo che non lasci alcun margine di dubbio in quanto cita chiaramente esempi che funzionano e come funzionano pure.
Marcelo,

7

Esegui sleepin una subshell:

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

Nota: su Linux è possibile fornire l'argomento sleep in secondi o con un suffisso s / m / h / d (per secondi, minuti, ore, giorni). Su BSD l'argomento deve essere in secondi


Ho un piccolo problema con questo metodo --- il flusso "hi" viene stampato nel mio prompt (nel stdin) e non nel mio stdout(come farebbe con un normale echo).
Arcticooling,

1
Se non vuoi che l'output nel tuo terminale sia confuso con i prompt e l'output di altri comandi dovrai reindirizzarlo da qualche parte
PiedPiper

Questo reindirizzamento non è riuscito @PiedPiper (sleep 10s; echo 'hi') & 1>. Ora leggo di più su questo.
Arcticooling il

2
Leggere la documentazione è sempre una buona idea :)
PiedPiper

1
@Arcticooling Sembra che tu sia confuso sul significato di stdine stdout. Non hanno nulla a che fare con dove appaiono le cose sul tuo terminale; invece, dovresti interpretarli rispetto ad un particolare processo (sostanzialmente, un programma). L'input standard ("stdin") per un processo è una fonte da cui il processo può leggere i dati e l'output standard del processo ("stdout") è una destinazione in cui può scrivere i dati. Queste fonti e destinazioni possono essere altri programmi o file o il terminale stesso (le cose digitate vanno su stdin e viene visualizzato tutto ciò che arriva a stdout).
David Z,

3

Ciò è fallito perché stai eseguendo il piping dell'output di echo "hi", che è solo hiper at, ma si ataspetta che il suo input possa essere eseguito dalla shell di sistema predefinita (di solito bash, ma a volte qualcosa di diverso a seconda del sistema).

Questo:

at 1m << EOF
echo "hi"
EOF

raggiungerà ciò che sembra stia cercando di fare. Usa un costrutto di shell chiamato 'qui documento', che è generalmente il modo accettato per fare questo tipo di cose (perché gestisce più righe meglio dell'uso del echocomando e non richiede la creazione di un nuovo file come sarebbe necessario con cat) e si traduce nell'equivalente un po 'più complicato usando echo:

echo 'echo "hi"' | at 1m

Probabilmente vale la pena notare che atinvierà qualsiasi output di comando all'utente che ha invocato il atcomando, invece di inviare l'output al terminale come sleepfarebbe un comando ritardato utilizzando in una subshell. In particolare, ciò significa che, a meno che non sia stata effettuata una certa personalizzazione del sistema o non si intenda leggere lo spool di posta locale, non sarà possibile eseguire l'output dei comandi at.


Per qualche motivo, entrambi gli esempi che mi hai dato mi danno un errore syntax error. Last token seen: m Garbled time . Non ho idea del perché. Uso Ubuntu 16.04, Bash 4.0. Forse l'hai fatto su un altro sistema. Anche quando scrivo atsenza ulteriori argomenti --- ottengo ancora lo stesso errore. Maggiori dati qui .
Arcticooling il

1
at 1mnon funziona con un posix compatibile at. Il comando dovrebbe essereat now + 1 minute
PiedPiper

@PiedPiper è corretto, 1m non è compatibile con le versioni POSIX compatibili at, stavo solo supponendo che tu avessi una versione che accettasse quella sintassi.
Austin Hemmelgarn,

@PiedPiper, at 1mnon è POSIX, ma le implementazioni compatibili con POSIX atsono libere di interpretarlo come desiderano, non rende atun'implementazione meno conforme interpretarla allo stesso modo now + 1 minuteche restituire un errore o significato un mese fa . IOW, è il at 1mcodice che non è POSIX.
Stéphane Chazelas,

2

Combina la risposta di @Peter Cordes e questa risposta /programming/23125527/how-to-return-to-bash-prompt-after-printing-output-from-backgrounded-function/23125687#23125687

Il codice sotto è da quest'ultima risposta, con un mio piccolo cambiamento. Compilalo in file a.out (qualunque sia il nome che ti piace)

#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;
}

Quindi eseguire il comando di seguito. (Ho inserito a.out in dir / tmp /, potrebbe essere necessario passare al tuo)

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

o

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

A proposito, kill -WINCH $$funziona benissimo per me con Bash 4.3 su Gentoo.


1

Sulla base delle risposte sopra, puoi avere il comando incorporato che dirige il suo output sul tuo terminale, in questo modo:

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

Il ttycomando restituisce il percorso del dispositivo del tuo terminale corrente, racchiudendolo in $(...)ha bash eseguirlo in una sotto-shell e il comando kill invia un segnale al processo corrente che bash ristamperà il suo prompt $ PS1.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.