en algún momento a partir de ahora haga algo (y tal vez también muestre el resultado en la consola)

12

Uso el servidor Ubuntu 16.04 y deseo usar la utilidad aten mi sesión actual para hacer algo dentro de 1 minuto (digamos, un echo), sin dar una fecha y hora específicas, solo 1 minuto antes de la hora actual.

Esto falló:

echo 'hi' | at 1m

La razón por la que elijo atmás sleepes porque el sueño perjudica la sesión actual y, por lo tanto, es más adecuado para retrasar los comandos en otra sesión, en lugar de con la que trabajamos la mayor parte del tiempo. AFAIR, atno se comporta de esta manera y no perjudicará mi sesión.

Actualización_1

Por la respuesta de Pied Piper, he intentado:

(sleep 1m; echo 'hi')  &

Tengo un problema con este método: la secuencia "hola" se imprime dentro de mi mensaje principal y también agrega un mensaje secundario vacío ( _) justo debajo del mensaje principal que lo contiene, vea:

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

Actualización_2

Por la respuesta de Peter Corde intenté:

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

Esto funciona correctamente en Bash 4.4, pero no en algunas versiones anteriores, aparentemente (ver comentarios en la respuesta). Yo personalmente uso Bash 4.3 en mis propios entornos.

Arcticooling
fuente
2
¡Desearía que las banderas de matar fueran de estilo GNU y pudieran reorganizarse para que no suene como "matar a la moza"!
NH.

Respuestas:

6

La secuencia "hola" se imprime en mi mensaje (en el stdin) y no en mistdout

No, es no "impreso en su stdin".

Si presionó Intro, no intentaría ejecutarse hicomo un comando. Es solo que el fondo se echoimprimió himientras el cursor estaba después de su solicitud.


Quizás desee imprimir una nueva línea principal , como (sleep 1m && echo -e '\nhi' &). (Ajuste según sea necesario para el echoen su shell. O use printfpara la portabilidad).

Puse el &interior del subshell para "rechazar" el trabajo en segundo plano, para que también evite el "ruido" de [1]+ Done. Con &&entre los comandos, se &aplica a toda la cadena de comandos compuestos, por lo que vuelve al indicador de comandos de inmediato en lugar de esperar sleepa salir como lo haría con(sleep 1; echo ... &)

Esto es lo que sucede (con 1 segundo de retraso):

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

Bash no sabe que echoimprimió algo, por lo que no sabe que necesita volver a imprimir su mensaje o limpiar la pantalla. Puede hacerlo manualmente con control-L.

Podría escribir una función de shell que obtenga bash para volver a imprimir su solicitud después de echofinalizar . Hacerlo echo "$PS1"no reproducirá ningún carácter ya escrito. kill -WINCH $$en mi sistema, bash vuelve a imprimir su línea de aviso sin borrar la pantalla, dejando hiuna línea sola antes del aviso. SIGWINCH se envía automáticamente cuando el tamaño de WINdow cambia, y la respuesta de bash hace lo que queremos.

Puede funcionar con otros shells, pero no estoy tratando de hacer que este sea 100% portátil / POSIX. ( Desafortunadamente, esto solo funciona en bash4.4, no bash4.3, o depende de alguna configuración que desconozco )

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

Podría envolver esto fácilmente en una función de shell que toma un argumento de suspensión y un mensaje.

bash 4.3 no vuelve a imprimir su solicitud después de SIGWINCH, por lo que esto no funciona allí. He shopt -s checkwinsizehabilitado en ambos sistemas, pero solo funciona en el sistema Bash 4.4 (Arch Linux).

Si no funciona, puede intentarlo (sleep 2 && echo -e '\nhi' && echo "$PS1" &), lo que "funciona" si la línea de comando está vacía. (También ignora la posibilidad que PROMPT_COMMANDse establece).


No hay una forma realmente limpia de hacer que la salida del terminal se mezcle con lo que sea que esté haciendo en su terminal más tarde, cuando se dispara el temporizador. Si estás en medio de desplazarte por algo less, podrías pasarlo por alto fácilmente.

Si está buscando algo con resultados interactivos, le sugiero que reproduzca un archivo de audio. por ejemplo, con un jugador de línea de comandos como mpv(buen fork de MPlayer2). O elija un archivo de video para que se abra una nueva ventana.

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

Es posible que desee echoabrir un nuevo xterm / konsole / gnome-terminal. Use una opción que mantenga el terminal abierto después de que salga el comando.

Peter Cordes
fuente
Te agradezco mucho, David, y lo he aprobado. Esto es realmente lo más cerca que tengo de lo que busco. ¿Hay alguna manera de actualizar el siguiente comando para emular un Enterevento de pulsación de tecla, justo después de que aparezca el eco, para que automáticamente vuelva al indicador principal de la consola ? (sleep 2 && echo -e '\nhi' && kill -WINCH $$ &).
Arcticooling
@Arcticooling: kill -WINCH $$ no actualizar el símbolo de la concha se ejecuta en el terminal. Ese era el punto de usarlo. Al presionar enter se enviaría un comando parcialmente escrito, pero WINCH no, como lo mostré. Si no ha escrito nada, aparece un mensaje vacío.
Peter Cordes
1
Si comenzaste a escribir rm -rf ~/some/directory, entrar en el momento incorrecto podría ejecutarse rm -rf ~/. (Consejo de seguridad: termine de escribir los trazados y luego controle-a y cambie lsa rm -rf, por lo que ingresar con dedos gordos Enter en cualquier momento no arruinará su día.)
Peter Cordes
Cableado, ejecuté (sleep 2 && echo -e '\nhi' && kill -WINCH $$ &)y después de que apareció el eco, recibí un mensaje vacío, solo después de presionar Entervolví al mensaje principal ... Lo siento si no te entiendo, soy bastante nuevo en Bash.
Arcticooling
@Arcticooling: estoy usando Bash 4.4 en Arch Linux, en un emulador de terminal Konsole. Esperaba que mi comando fuera portátil al menos para otras versiones de bash, pero tal vez no :( Sí, solo lo probé en Bash 4.3 dentro de una screensesión (y solo a través de SSH) en un sistema Ubuntu más antiguo, y obtuve el comportamiento que usted describe.
Peter Cordes
13

Lo correcto en el uso es at <timespec>dónde <timespec>está la especificación de tiempo. También puede usar la -fopción para especificar el archivo que contiene los comandos para ejecutar. Si -fno se utiliza la redirección, leerá los comandos para ejecutar desde el stdin (entrada estándar).

En su ejemplo, para ejecutar "algún comando" (elegí "algún comando" para que sea "echo hola" en el ejemplo a continuación) un minuto después de presionar enter (ahora), lo que se pretende <timespec>usar es now + 1 minute. Entonces, para obtener el resultado que desea con una solución de una sola línea, utilice el siguiente comando:

echo 'echo hi' | at now + 1 minute

Esto se supone (y lo hará) para ejecutar el echo hicomando después de un minuto. El problema aquí es que el echo hicomando será ejecutado por el comando at en un tummy ficticio y la salida se enviará al buzón del usuario (si está configurada correctamente), lo que requiere una explicación más amplia sobre cómo configurar un buzón en una máquina unix y no es parte del alcance de esta pregunta). La conclusión es que no podrá ver directamente el resultado echo hien el mismo terminal en el que emitió el comando. La alternativa más fácil es redirigirlo a "algún archivo", por ejemplo:

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

En el ejemplo anterior, "algún archivo" es /tmp/at.outy el resultado esperado es que el archivo at.outbajo / tmp se crea después de un minuto y contiene el texto 'hola'.

Además del now + 1 minuteejemplo anterior, se pueden usar muchas otras especificaciones de tiempo, incluso algunas complejas. El comando at es lo suficientemente inteligente como para interpretar los que son legibles para humanos como los ejemplos a continuación:

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

Consulte la página de manual de at para obtener más información sobre las posibles especificaciones de tiempo, ya que las posibles variaciones son bastante extensas y pueden incluir fechas, tiempos relativos o absolutos, etc.

Marcelo
fuente
2
atde forma predeterminada, envía la salida por correo, pero debe configurarse correctamente para funcionar.
Simon Richter
Ahora ofrezco recompensas de 100 repeticiones por una respuesta. Lea mi mensaje de recompensa a continuación y edítelo para explicar más sobre qué es at <timespec>y la bandera que utilizó y si se ajusta a Ubuntu 16.04 xenial.
Arcticooling
Ok, aumenté el nivel de detalle en la respuesta para que sea más didáctico ahora. Puede sonar un poco largo para algunos, pero creo que no deja margen para las dudas, ya que claramente cita ejemplos que funcionan y cómo funcionan también.
Marcelo
7

Ejecute el sleepen una subshell:

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

Nota: en Linux puede dar el argumento para dormir en segundos o con un sufijo s / m / h / d (por segundos, minutos, horas, días). En BSD el argumento tiene que estar en segundos

Flautista de Hamelín
fuente
Tengo un pequeño problema con este método: la secuencia "hola" se imprime en mi solicitud (en el stdin) y no en mi stdout(como lo haría con un mensaje regular echo).
Arcticooling
1
Si no desea que la salida en su terminal se mezcle con las indicaciones y la salida de otros comandos, tendrá que redirigirla a algún lugar
PiedPiper,
Esta redirección falló @PiedPiper (sleep 10s; echo 'hi') & 1>. Ahora leo más sobre esto.
Arcticooling
2
Leer la documentación siempre es una buena idea :)
PiedPiper
1
@Arcticooling Parece que estás confundido acerca de los significados de stdiny stdout. No tienen nada que ver con dónde aparecen las cosas en su terminal; en su lugar, debe interpretarlos con respecto a un proceso particular (básicamente, un programa). La entrada estándar ("stdin") para un proceso es una fuente desde la cual el proceso puede leer datos, y la salida estándar del proceso ("stdout") es un destino en el que puede escribir datos. Estas fuentes y destinos pueden ser otros programas o archivos, o el terminal en sí (las cosas que escribe van a stdin y se muestra todo lo que viene a stdout).
David Z
3

Eso falló porque está canalizando la salida de echo "hi", que es solo hipara at, pero atespera que su entrada pueda ejecutarse mediante el shell del sistema predeterminado (generalmente bash, pero a veces algo diferente dependiendo del sistema).

Esta:

at 1m << EOF
echo "hi"
EOF

logrará lo que parece estar tratando de hacer. Utiliza una construcción de shell llamada 'documento aquí', que generalmente es la forma aceptada de hacer este tipo de cosas (porque maneja varias líneas mejor que usar el echocomando y no requiere crear un nuevo archivo como lo necesitaría con cat), y se traduce al equivalente algo más complicado usando echo:

echo 'echo "hi"' | at 1m

Probablemente valga la pena señalar que atenviará cualquier salida de comando al usuario que invocó el atcomando, en lugar de enviar la salida al terminal como lo sleepharía un comando retrasado al usarlo en una subshell. En particular, esto significa que a menos que haya realizado alguna personalización del sistema o tenga la intención de leer su cola de correo local, no podrá obtener la salida de los comandos a través de at.

Austin Hemmelgarn
fuente
Por alguna razón, los dos ejemplos que diste me dan un error syntax error. Last token seen: m Garbled time . No tengo ni idea de porqué. Yo uso Ubuntu 16.04, Bash 4.0. Tal vez lo hiciste en otro sistema. Incluso cuando escribo atsin más argumentos --- sigo teniendo este mismo error. Más datos aquí .
Arcticooling
1
at 1mno funciona para un posix compatible at. El comando debería serat now + 1 minute
PiedPiper
@PiedPiper es correcto, 1m no es compatible con versiones compatibles con POSIX de at, solo estaba asumiendo que tenía una versión que aceptaba esa sintaxis.
Austin Hemmelgarn
@PiedPiper, at 1mno es POSIX, pero las implementaciones compatibles con POSIX atson libres de interpretarlo como lo deseen, no hace que una atimplementación sea menos compatible para interpretarlo con el mismo significado now + 1 minuteque devolver un error o significado hace un mes . IOW, es el at 1mcódigo que no es POSIX.
Stéphane Chazelas
2

Combine la respuesta de @Peter Cordes y esta respuesta /programming/23125527/how-to-return-to-bash-prompt-after-printing-output-from-backgrounded-function/23125687#23125687

El siguiente código es de la última respuesta, con un pequeño cambio mío. Compílalo para archivar a.out (como quieras)

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

Luego ejecute el comando a continuación. (Puse a.out en dir / tmp /, es posible que deba cambiar el suyo)

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

o

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

Por cierto, kill -WINCH $$funciona bien para mí con Bash 4.3 en Gentoo.

Bruce
fuente
1

Sobre la base de las respuestas anteriores, puede hacer que el comando incrustado dirija su salida a su terminal, así:

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

El ttycomando devuelve la ruta del dispositivo de su terminal actual, encerrándolo en $(...)bash, ejecútelo en un sub-shell, y el comando kill envía una señal al proceso actual que hará que bash vuelva a imprimir su solicitud $ PS1.

usuario1404316
fuente