Llevo un tiempo metido en la migración de una base de datos. No solo se trata de dos bases de datos distintas, sino que además sus motores son también distintos. En este sentido, estoy utilizando Python para migrar los datos de una a la otra. Durante estos días estoy haciendo diversas pruebas, antes de crear un servicio. Sin embargo, quería dejar un proceso corriendo durante horas, en concreto durante toda la noche, pero evidentemente no quería quedarme yo a vigilarla. Así, necesitaba salir del terminal desde el que había lanzado el proceso, sin detenerlo. En este sentido, he echado mano de nohup
que ya he utilizado en otras ocasiones, como en el caso de convertir archivos de vídeo.
Así este artículo va dedicado a nohup
para que puedas sacarle partido cuando lo necesites.
nohup
Seguro que en mas de una ocasión te ha sucedido que estabas ejecutando algún proceso en el terminal, y por salirte de él, has terminado el trabajo que se estaba haciendo. Por supuesto, en ese preciso momento, has echado por tu boca sacos y culebras, y te has acordado de todo lo que uno se puede acordar.
Tener un servidor, como puede ser perfectamente una Raspberry Pi, y no poder dejar un proceso en marcha, porque tienes que cerrar la conexión, es desaprovechar las posibilidades que te ofrece cualquier servidor. En este sentido tienes diferentes opciones para dejar el proceso corriendo en segundo plano, como pueden ser tmux
o screen
.
Sin embargo, como he comentado en la introducción, hace poco me sucedió, que quería dejar un proceso corriendo, y no tenía ninguna de estas herramientas. Y lo que es peor, tampoco tenía posibilidad de instalarlas. Así que recordé sobre nohup
y quise sacarle el máximo partido posible.
Alternativas
Probablemente te preguntas porque no utilizo otras herramientas como puede ser tmux
o screen
. La cuestión es que en el equipo donde estoy haciendo la migración, no solo no tengo ninguna de estas dos herramientas, sino que además no tengo oportunidad de instalarlas. Me tengo que conformar con lo que tengo. O mejor dicho, tengo que aprovechar todo lo que tengo.
Esta es una de las razones por las que agradezco que en el mundo Linux haya tal cantidad de herramientas. Es posible, que en alguna ocasión te hayas preguntado, para que tantas duplicidades de herramientas. Pues como se dice, siempre hay un roto para un descosido. Y aquí tienes una clara justificación.
Utilizando nohup
Ahora que ya tienes una justificación, para el uso de nohup
, ahora es el momento de adentrarse. Lo primero es indicarte que nohup
es un comando que permite obviar la señal HUP
. Esta señal se envía a los diferentes procesos que están corriendo en un terminal para que se cierren y finalicen sus trabajos. Sin embargo, en ocasiones, te interesa dejar un proceso corriendo aunque tu salgas del terminal. Te interesa dejar un proceso corriendo en segundo plano. Aquí es donde interviene nohup
que lo que hace es interceptar esta señal, de forma que nunca llegará a tu proceso, y quedará corriendo en segundo plano por los siglos de los siglos o hasta que termine el proceso.
El uso es realmente sencillo. Tan solo tienes que anteponer nohup
al comando que quieres que se quede en ejecución en segundo plano. Por ejemplo,
nohup comando &
Simplemente indicarte que si quieres guardar la salida del terminal en un archivo tienes que indicarlo. Por ejemplo, nohup comando > archivo
. En caso de que no se lo indiques, el guardará un archivo nohup.out
con la salida estándar. Igualmente, si quieres que también los errores vayan allí, tendrás que seguir las indicaciones del capítulo sobre redirigir entrada y salida en Linux del tutorial sobre el terminal, que resumiendo sería algo como lo que ves a continuación,
nohup comando > archivo 2>&1 &
Y si quieres estar al tanto de lo que se produce en tu comando, puedes utilizar tail
, tal y como te indico en el artículo sobre procesar texto con tail, que corresponde también al tutorial sobre el terminal, que resumiendo sería algo como,
tail -f archivo
Un ejemplo
Para que puedas probar todo esto en primer plano, he escrito un sencillo script en Python, test.py
, que puedes ver a continuación,
import time
import datetime
counter = 0
while True:
counter += 1
print('{0} - {1}'.format(counter, datetime.datetime.now()))
time.sleep(1)
Lo único que hace este script es imprimir un número consecutivo cada segundo seguido de la fecha y hora a la que lo ha hecho. Esto de forma ininterrumpida hasta que tu lo detengas. Así, por ejemplo la salida puede ser algo como lo que ves a continuación,
1 - 2019-05-30 20:34:42.583360
2 - 2019-05-30 20:34:43.584496
3 - 2019-05-30 20:34:44.585719
De esta manera si lo que quieres es dejarlo corriendo es segundo plano, debes ejecutar la siguiente instrucción,
nohup python -u test.py > salida.out 2>&1 &
La opción -u
es para que la salida estándar y el error no tengan un buffer o memoria intermedia, de forma que conforme lo puedas ver en tiempo real.
Trabajando con procesos en segundo plano
Llegados a este punto, es posible que hayas mandado un proceso a segundo plano y ahora lo quieras recuperar. Primero partimos de que continuas en el mismo terminal, es decir, no has salido de la sesión que iniciaste.
En este sentido, te recomiendo que leas el artículo sobre procesos en segundo plano en Linux.
Si quieres ver todos los procesos que has enviado a segundo plano, tan solo tienes que ejecutar la orden jobs
. Así, por ejemplo, en mi caso, he puesto en marcha diferentes procesos, de forma que al ejecutar jobs
el resultado es el siguiente,
[1]+ Detenido python test.py
[2] Detenido python test.py
[3]- Detenido python test.py
[4] Ejecutando nohup python -u test.py > salida.out 2>&1 &
Como ves el proceso con nohup
lo tienes en segundo plano, y lo tienes en funcionamiento. Ahora podrías recuperarlo de forma sencilla utilizando fg %4
, tal y como te expliqué en el artículo que te he mencionado anteriormente sobre procesos en segundo plano.
El problema, seguramente lo encuentres en el caso de que salgas de la sesión de terminal en la que te encuentras, o abras otra sesión en otro terminal, y quieras recuperar el proceso. Si bien es cierto, que hay diferentes herramientas que aparentemente deberían de ayudarte a traer el proceso a primero plano, lo cierto es que, hasta la fecha, no he conseguido que ninguna me funcione. En el momento en que salgo de la sesión no puedo recuperar el proceso.
Sin embargo, llegados a este punto me pregunto, ¿de verdad necesitas traer el proceso a primer plano?. Dado que has redirigido tanto la salida como los errores a un archivo ¿para que necesitas traer el proceso a primer plano?
Perfectamente puedes consultar la salida de tu proceso en el archivo salida.out
, y en su caso finalizar el proceso.
¿Y como finalizar el proceso? Si estás en el mismo terminal, tan solo necesitas un kill %4
. En el caso de que estés de regreso, tendrás que buscar el proceso con ps -ef | grep python
y posteriormente, con el número del proceso directamente matarlo kill -9 <PID>
.
Conclusiones
Se trata de una herramienta muy interesante para el caso que te he comentado anteriormente, si bien, en un futuro artículo, tengo intención de abordar screen
por todas las posibilidades que ofrece.