¿Por qué algunos comandos 'cuelgan' el terminal hasta que hayan terminado?

22

A veces ejecuta un programa desde la terminal, por ejemplo, lxpanel . El terminal no lo regresará al indicador, se bloqueará. Puede presionar Ctrl+ Cpara volver al indicador, pero eso matará lxpanel. Sin embargo, presionar Alt+ F2(que abre una ventana para tomar un comando) y ejecutar lxpanelfunciona correctamente.

¿Por qué es esto? ¿Qué es diferente entre ejecutar un comando desde la terminal y desde la ventana 'ejecutar' que aparece cuando presiona Alt+ F2?

lxpanel aquí solo se usó como ejemplo. He experimentado esto con múltiples programas

sqram
fuente
1
Consejo: GNU Screen ( screen) puede, entre otras cosas, usarse para "envolver" procesos de ejecución más larga. Puede desconectarse de él, volver al shell, luego volver a conectar y ver la salida del proceso en ejecución. La reconexión incluso se puede hacer desde otro terminal, SSH, etc. También puede haber otros programas que le permitan hacer este tipo de cosas.
poplitea

Respuestas:

28

Por defecto, el terminal ejecutará el programa en primer plano, por lo que no terminará en el shell hasta que el programa haya finalizado. Esto es útil para los programas que leen desde stdin y / o escriben en stdout; generalmente no desea que muchos de ellos se ejecuten a la vez. Si desea que un programa se ejecute en segundo plano, puede iniciarlo así:

$ lxpanel &

O si ya se está ejecutando, puede suspenderlo con Ctrl+ Zy luego ejecutarlo bgpara moverlo a segundo plano. De cualquier manera, terminará con un nuevo indicador de shell, pero el programa aún se está ejecutando y su salida aparecerá en la terminal (por lo que puede aparecer repentinamente mientras está escribiendo)

Algunos programas (típicamente demonios) bifurcarán un proceso separado cuando comiencen, y luego dejarán que el proceso principal salga inmediatamente. Esto permite que el programa siga ejecutándose sin bloquear su shell

Michael Mrozek
fuente
Entonces, ¿qué está haciendo realmente el sistema cuando ejecuta el programa a través de la ventana 'ejecutar' presionando Alt + f2? (al menos en gnome y openbox, alt + f2 hace eso). Le pregunto porque tan pronto como escribe el comando, el programa se inicia y el cuadro desaparece. ¿Es solo agregar un & a él?
sqram
2
@lyrae: por defecto, el shell espera a que el programa se complete antes de continuar con la sesión del shell, no se "cuelga", por ninguna definición de "hang"; alt + f2 no ​​espera el programa. La razón por la que el shell espera a que el programa se complete es porque el shell puede redirigir lo que el usuario escribió en el shell a la entrada estándar del programa y / o mostrar la salida estándar del programa. Dado que alt + f2 se usa principalmente para iniciar un programa GUI, alt + f2 no ​​ofrece la posibilidad de usar entrada / salida estándar y, por lo tanto, no necesita esperar.
Lie Ryan
1
@lyrae: alt + f2 no ​​hace nada especial para iniciar el programa en segundo plano; es el shell lo que está haciendo algo especial, agregando '&' es la funcionalidad del shell. Al iniciar un comando sin '&', el shell redirige la entrada estándar del programa a su propia entrada estándar y la salida estándar del programa a su propia salida estándar (un poco artificial, ya que el shell también proporciona muchos otros servicios, como interceptar Ctrl -C, para enviar un comando de señal SIGINT al programa en primer plano). El '&' le dice al shell que no haga eso y solo inicie el programa (también ideado).
Lie Ryan
1
@LieRyan parte de lo que está diciendo que hace el shell, de hecho, lo maneja el controlador de terminal del kernel, y "with &" es generalmente más "especial" que "sin &", aparte de eso el shell llama a wait () [o waitpid o equivalente] que no se realiza con alt-f2.
Random832
6

Cuando inicia un programa en una terminal, la terminal se "colgará" hasta que su programa se detenga. Al presionar Ctrl+ c, está cerrando su programa y, por lo tanto, vuelve al indicador. Verá esto con todas las aplicaciones GUI, pruebe Firefox, por ejemplo.

Cuando utiliza algún otro método, como Alt + F2 o hace clic en los menús, su programa se inicia en segundo plano para que no ocurra nada extraño (y de todos modos no hay un símbolo del sistema).

Si aún desea iniciar aplicaciones GUI desde la terminal, agregue &al final de su comando, así

lxpanel &

Esto le dice a la terminal que se ejecute lxpanelen segundo plano y le dé otro aviso de inmediato.

phunehehe
fuente
3

Los programas se ejecutan a través de un shell que se ejecuta en primer plano de ese shell de forma predeterminada. Esto hace que el shell suspenda la operación y dirija stdin / stdout / sterr desde el terminal al programa. Los programas que se ejecutan a través del entorno de escritorio se bifurcan , lo que hace que se ejecuten independientemente del programa que los ejecutó. Esto se puede simular en la mayoría de los shells agregando &a al comando, aunque esto aún conectará std * al terminal (aunque leer desde stdin en un programa en segundo plano tiene más complicaciones).

Ignacio Vazquez-Abrams
fuente
2

Los fondos & bien, a excepción de los programas que regresan que requieren interacción con la consola más tarde (por ejemplo, una "apt -y update &" que eventualmente ingresa al estado STOP ya que quiere preguntarle al usuario una pregunta "¿realmente realmente forzar?" Mucho más tarde .... cuando ya nadie está mirando).

Para tapar ese agujero e informar el proceso, un terminal realmente nunca estará disponible para él, agrego un <& - a algunos de mis comandos, separándolos por completo del terminal activo diciéndoles que STDIN ya no es posible. Asegúrese de que / bin / bash es su shell si lo usa. El script continuará registrando cualquier error relacionado con la ausencia de pseudoterminal disponible para emitir cualquier aviso.

Por ejemplo:

`./runme.sh &> runme.log <&- & disown`

es mi mejor manera de desvincularse de la sesión actual de terminal. Tanto STDOUT como STDERR se registran en runme.log, no importará si su consola o shell finalizan antes o si cierra sesión / su en una cuenta diferente (no hay basura en la terminal de runme), y gracias a repudiar incluso al padre-hijo La relación PID se elimina.

ACTUALIZACIÓN: incluso con eso he tenido problemas con un semáforo que lo asocia con el nombre del padre original, así que ahora recomiendo en su lugar:

at now <<< "(cmd1; cmd2; etc.) &> logfile.log"

Por supuesto, elimine &> si desea que se le envíe por correo electrónico la salida de CRON, o redirija todo a / dev / null en lugar de un archivo.

Marcos
fuente
Una forma un poco menos complicada de lograr lo que comencé a usar esat now <<< "(cmd1; cmd2; etc.) &> logfile.log"
Marcos el