Linux / Comando / nohup: mantener tareas al cerrar la terminal

nohup es una herramienta que ejecuta un comando para que ignore la señal SIGHUP, que puede enviarse cuando se interrumpe la conexión del terminal. Para continuar trabajando incluso después de cerrar sesión, generalmente se recomienda usar nohup junto con el símbolo de ejecución en segundo plano &, y también especificar explícitamente los archivos de entrada y salida estándar.

Los nombres worker.sh, backup.sh y worker son ejemplos: prepare su programa, sus dependencias y permisos de ejecución, y compruébelo primero en primer plano. Use un directorio propio con permisos de escritura para los registros; > sobrescribe archivos existentes. La forma de lanzamiento es:

nohup ./worker.sh > worker.log 2>&1 < /dev/null &

Sin embargo, nohup no es un administrador de servicios que supervise o reinicie procesos. Para servicios de larga duración que requieran inicio automático tras un reinicio, reinicio en caso de fallo o rotación de registros, una herramienta de gestión de servicios como systemd es más adecuada.

¿Para qué sirve el comando nohup?

nohup ejecuta el comando después de configurar para que ignore la señal de hangup (SIGHUP). Al cerrar el terminal o terminar la conexión SSH, la señal SIGHUP puede enviarse al shell y a los procesos relacionados; al ignorarla, hay una mayor probabilidad de que el trabajo continúe ejecutándose.

Como se puede ver en la descripción oficial de nohup de GNU Coreutils, nohup por sí mismo no envía el comando al fondo. Para continuar con otros trabajos en la terminal actual, se debe añadir & al final del comando por separado.

Componente Lo que hace Lo que no hace
nohup Inicia el comando con SIGHUP ignorada. No ejecuta automáticamente en segundo plano.
& Permite que la shell ejecute el comando como trabajo en segundo plano. No garantiza que se pueda ignorar SIGHUP.
Redirección de salida Envía la salida estándar y los errores a un archivo de registro especificado. No hay límite de tamaño de registro ni eliminación automática.

Sintaxis básica y forma de ejecución recomendada

Sintaxis básica

Escriba en orden el comando y los argumentos que desea ejecutar después de nohup.

nohup command [arg ...]

Por ejemplo, para ejecutar backup.sh en el directorio actual, introduzca lo siguiente.

nohup ./backup.sh

Esta forma ignora SIGHUP, pero se ejecuta en primer plano. Por lo tanto, es difícil ingresar el siguiente comando en la misma shell hasta que el comando termine.

Ejecución en segundo plano y almacenamiento de registros

En el trabajo real, es más fácil de gestionar especificar la ejecución en segundo plano y la ruta del registro juntos.

nohup ./backup.sh > backup.log 2>&1 < /dev/null &
  • > backup.log registra la salida estándar en un nuevo archivo de registro. Si el mismo archivo existe, sobrescribirá el contenido existente.
  • 2>&1 envía los errores estándar al mismo lugar que la salida estándar actual.
  • < /dev/null reemplaza la entrada estándar con una fuente que devuelve fin de archivo (EOF) para que el programa no espere la entrada del terminal.
  • El último & ejecuta el comando en segundo plano.

Para agregar nuevo contenido al final de un registro existente, use >> en lugar de >.

nohup ./backup.sh >> backup.log 2>&1 < /dev/null &

Guardar PID inmediatamente después de la ejecución

Inmediatamente después de ejecutar un comando en segundo plano, $! contiene el ID de proceso (PID) del trabajo iniciado más recientemente en segundo plano. Para verificar el estado o finalizarlo más tarde, es conveniente guardar este valor en un lugar seguro.

nohup ./backup.sh > backup.log 2>&1 < /dev/null &
job_pid=$!
printf '%s\n' "$job_pid" > backup.pid

Coloque el archivo PID en un directorio donde solo el usuario que administra el trabajo pueda escribir. Si quedan archivos PID antiguos, el mismo número podría ser usado por otro proceso más tarde, por lo que es seguro verificar también el comando y la hora de inicio antes de finalizar.

¿Cómo se manejan la entrada y salida estándar?

entrada estándar

En la implementación de GNU, si la entrada estándar está conectada a un terminal, nohup se convierte en una fuente de entrada ilegible. Este comportamiento ayuda a reducir situaciones en las que el programa se detiene esperando la entrada después de que el terminal ha desaparecido. Para minimizar las diferencias de implementación y aclarar la intención, se puede escribir < /dev/null directamente en el comando.

Salida estándar y nohup.out

Si la salida estándar está dirigida a la terminal y no se especifica una redirección separada, GNU nohup continúa escribiendo la salida en nohup.out en el directorio actual. Si no se puede crear un archivo en el directorio actual, se intenta nohup.out en el directorio de inicio del usuario, y si no se puede escribir en ninguno de los dos lugares, el comando no se ejecuta.

Si varias tareas comparten el mismo nohup.out, será difícil distinguir de qué tarea es cada registro y el archivo puede seguir creciendo. Es mejor especificar un archivo de registro con un nombre y una política de conservación por cada tarea.

error estándar

Cuando el error estándar se dirige a la terminal, GNU nohup generalmente lo envía al mismo destino que la salida estándar. Sin embargo, según la shell, el sistema operativo y la redirección aplicada anteriormente, quien lea los resultados podría malinterpretarlos, por lo que es seguro indicar la intención explícitamente, como 2>&1. El orden de las conexiones de entrada y salida en la shell afecta los resultados, por lo que se pueden consultar los principios detallados en Explicación de redirección de entrada y salida de GNU Coreutils.

Comprobando el estado de ejecución y los registros

Verificando el proceso con el PID guardado

Si hay un PID guardado justo después de la ejecución, puede pasarlo directamente a ps para comprobar el estado.

job_pid=$(cat backup.pid)
ps -p "$job_pid" -o pid,ppid,stat,etime,cmd

PID es el número de proceso, PPID es el número de proceso padre, STAT es el estado y ELAPSED es el tiempo de ejecución. No asuma que es la tarea deseada solo porque existe un PID, y también verifique la última columna del comando.

Buscar un proceso por nombre

Si no se ha guardado el PID, puede buscarlo en la línea de comandos con pgrep.

pgrep -af 'backup.sh'

Dado que otros procesos que contienen la misma cadena también pueden ser buscados, debe verificar toda la línea de comandos del resultado. Simplemente concatenar el resultado ps con grep no es adecuado para la automatización, ya que el propio comando de búsqueda tiende a aparecer también.

Verificar los registros en tiempo real

Al usar tail -f, puede seguir verificando el contenido que se agrega al final del archivo.

tail -f backup.log

Para finalizar la supervisión de registros, presione Ctrl+C. Esto solo terminará tail y no finalizará la tarea original que genera los registros. Puede ver más detalles sobre cómo especificar líneas y seguir archivos en Uso del comando tail.

Finalizar procesos iniciados con nohup

Primero solicitar una terminación normal

Después de verificar el PID y el comando objetivo, ejecutar kill enviará por defecto la señal SIGTERM. Si el programa tiene un código para manejar la terminación, tendrá la oportunidad de cerrar archivos y limpiar estados.

job_pid=$(cat backup.pid)
ps -p "$job_pid" -o pid,ppid,stat,etime,cmd
kill "$job_pid"

Verificar si se ha terminado

Espere un momento y luego consulte el mismo PID de nuevo.

ps -p "$job_pid" -o pid,stat,etime,cmd

Si un script de shell ha creado varios procesos hijos, incluso si termina uno de los padres, los hijos pueden permanecer. Primero, verifique el árbol de procesos y el grupo de procesos, y si el programa que está utilizando proporciona un comando de terminación oficial, utilícelo primero.

Usar la terminación forzada como último recurso

Si termina inmediatamente un proceso solo porque no responde a SIGTERM, puede que los datos no se guarden o los archivos temporales no se eliminen. Asegúrese de que la causa y el objetivo sean precisos y use SIGKILL solo como último recurso.

kill -KILL "$job_pid"

Ejecutar tuberías y comandos compuestos

Agrupar en un solo comando de shell

Para ejecutar una tubería, múltiples redirecciones o operadores condicionales como un solo trabajo, puede pasar la cadena de comandos al shell.

nohup sh -c 'producer | consumer' > pipeline.log 2>&1 < /dev/null &

producer y consumer son marcadores para programas reales. Un nuevo shell interpreta la canalización; por defecto, su estado corresponde al último comando, así que un fallo del productor puede quedar oculto. No inserte valores externos no fiables en la cadena. La relación de los operadores se explica en Uso de operadores de conexión de comandos de Bash.

Cuando no se ven los registros inmediatamente

Si el proceso está en ejecución pero los registros aparecen con retraso, el almacenamiento en búfer de salida del programa puede ser la causa más que nohup. Primero, verifique la configuración de vaciado de registro del propio programa. En entornos GNU, si el programa es compatible con el método de salida, también se puede solicitar el almacenamiento en búfer por línea con stdbuf.

nohup stdbuf -oL -eL ./worker > worker.log 2>&1 < /dev/null &

stdbuf no es efectivo para todos los programas. Puede no aplicarse si el programa restablece su propio búfer o utiliza métodos específicos de entrada/salida.

Límites de nohup y criterios para elegir otras herramientas

Funciones que nohup no proporciona

nohup es una herramienta de ejecución simple que cambia la forma en que se maneja una señal. No proporciona las siguientes funciones.

  • Inicio automático después del reinicio del sistema
  • Reinicio automático si el proceso termina de manera anormal
  • Gestión del orden de inicio de los servicios dependientes
  • Limitación de recursos como CPU y memoria y monitoreo del estado
  • Limitación del tamaño de archivos de registro, compresión, almacenamiento y eliminación
  • Conservación de sesiones de terminal interactivas

Diferencias con systemd, tmux y screen

Herramientas Situaciones adecuadas Características
nohup Trabajos por lotes no interactivos que se ejecutan temporalmente Es simple, pero no tiene funciones de supervisión, reinicio y rotación de registros
systemd Servicios que se ejecutan de manera continua en un servidor Puede configurar la integración de arranque, la política de reinicio, las dependencias, la gestión de registros y recursos.
tmux·screen Tareas interactivas a las que debe volver más tarde Se puede separar y volver a conectar una sesión de terminal virtual.
Programador de tareas Tareas que se ejecutan en un momento o intervalo determinado Se administran el momento de ejecución y el historial mediante cron o una cola de tareas dedicada.

Diferencia con disown

disown es una función integrada en el shell que algunos intérpretes como Bash utilizan para eliminar trabajos ya iniciados de la lista de trabajos del shell o para cambiar la forma en que se manejan las señales de hangup. Por otro lado, nohup es un programa externo que hace que SIGHUP sea ignorado desde el momento en que se inicia el comando. Las opciones y el comportamiento de disown varían según el shell, por lo que en scripts portables se debe consultar la documentación del shell actual.

Lista de verificación para ejecutar de manera segura

  • Ruta: Especifique los scripts, archivos de configuración y archivos de registro con rutas absolutas siempre que sea posible. Esto permite usar los mismos archivos aunque la ubicación de inicio de sesión cambie.
  • Permisos: Verifique que la contraseña, el token o la información personal no queden en los registros y limite los permisos de los archivos.
  • Tamaño: Configure logrotate o la política de retención de registros del programa para que los registros no continúen creciendo indefinidamente.
  • Ejecución duplicada: Asegúrese de que la misma tarea pueda ejecutarse varias veces al mismo tiempo de manera segura. Si es necesario, use archivos de bloqueo o la función de ejecución única del programa.
  • Entorno: En la ejecución no interactiva, el directorio de trabajo, PATH, la configuración regional y las variables de entorno pueden diferir del shell de inicio de sesión, por lo que especifique los valores necesarios.
  • Argumentos sensibles: Si se pasan contraseñas o tokens como argumentos de línea de comandos, otros usuarios pueden verlos en la lista de procesos. Utilice archivos de credenciales o métodos de almacenamiento seguro que admita el programa.
  • Procedimiento de finalización: Registre el PID inmediatamente después de la ejecución y prepare el procedimiento de finalización normal junto con la verificación de procesos hijos restantes.

Preguntas frecuentes

¿Si cierro la ventana de SSH, el trabajo nohup se mantiene sin falta?

nohup inicia el comando con SIGHUP ignorada, pero no garantiza su supervivencia frente a otras señales, un reinicio, una política de cierre de sesión que termine procesos o un programa que cambie ese manejo. Desconecte la entrada y las salidas del terminal y utilice un gestor de servicios para tareas que necesiten supervisión.

¿Cómo puedo evitar crear el archivo nohup.out?

Puede especificar directamente la salida estándar y el error estándar. Solo se pueden enviar trabajos que no necesiten ningún registro a /dev/null, pero como también desaparece la información para diagnosticar problemas, normalmente se recomienda un archivo de registro separado para operaciones de mantenimiento.

nohup ./worker > /dev/null 2>&1 < /dev/null &

¿Cuál es la razón por la que no se ven los trabajos en jobs?

jobs solo muestra las tareas que el shell está gestionando actualmente. Después de cerrar sesión y conectarse a un nuevo shell, la lista de tareas del shell anterior no se transferirá, por lo que no aparecerá en jobs. Utilice el PID guardado y ps, o la función de consulta de estado de la herramienta de gestión de servicios.

¿Qué significa el código de salida de nohup?

GNU nohup devuelve 125 por un fallo propio si POSIXLY_CORRECT no está activada; 126 si encuentra el comando pero no puede ejecutarlo; 127 si no lo encuentra; y el estado del programa en los demás casos. Con POSIXLY_CORRECT, sus fallos propios usan 127. Al lanzar con &, $? inmediato no es el resultado final: desde el mismo shell padre use wait "$job_pid" para recogerlo mientras conserve ese hijo. Tras cerrar esa sesión, consulte los registros o un gestor de trabajos.

Resumen

nohup ejecuta el comando para ignorar SIGHUP que puede ocurrir al cerrar sesión o al finalizar la terminal. Las tareas no interactivas habituales usan junto con nohup, & y redirección explícita de entrada/salida estándar, y es fácil de gestionar si se guarda el PID inmediatamente después de la ejecución.

Si una tarea debe comenzar incluso después de un reinicio o necesita recuperación automática en caso de fallo, elija un administrador de servicios como systemd en lugar de nohup. Para ver de un vistazo otras herramientas básicas, se puede consultar Lista de comandos frecuentemente usados en Linux.