El mejor truco del comando `fg` : cuando `Ctrl+Z` salva tu sesión de terminal
Publicado el 18 April 2026
- El problema: un terminal ocupado
- Los tres comandos indispensables
- Escenario 1: El build largo
- Escenario 2: El editor olvidado
- Escenario 3: El proceso opencode suspendido
- Escenario 4: Gestionar varios trabajos simultáneamente
- Diferencias entre fg, bg, Ctrl+Z, Ctrl+C y &
- El ciclo de vida completo de un trabajo
- Diagrama resumido
- Memoria técnica: las señales
- Conclusión
Lanzas`./gradlew build`, el terminal está bloqueado durante 3 minutos, y necesitas hacer otra cosa mientras esperas? No es necesario abrir una nueva pestaña.`Ctrl+Z`suspende el proceso,`fg`Lo lleva exactamente donde lo dejaste. Es el tip de Unix más subestimado del día a día de un desarrollador.
El problema: un terminal ocupado
Todo desarrollador ha conhecido esta situación:
$ ./gradlew build
> Building...
El terminal está bloqueado. No puedes escribir ningún comando. Y necesitas consultar un archivo, lanzar un`git status`, o comprobar un puerto ocupado.
@startuml skinparam backgroundColor #FEFEFE actor Développeur as dev participant "Terminal" as term participant "Gradle\n( processus )" as gradle dev -> term : ./gradlew build term -> gradle : Ejecuta el build gradle -> term : Ocupa el terminal\n(pas de prompt) dev -> term : quiere escribir un comando term --> dev : Terminal bloqueado note right of dev El desarrollador está paralizado durante toda la duración del build end note @enduml
La mayoría de los desarrolladores abren una nueva terminal. Pero existe una solución más elegante, más rápida y nativa: la gestión de los trabajos.
Los tres comandos indispensables
Ctrl+Z — Suspender (SIGTSTP)
`Ctrl+Z`envía la señal`SIGTSTP`al proceso en primer plano. El proceso essuspendido— no matado — y el terminal recupera su prompt.
$ ./gradlew build
> Building...
^Z
[1]+ Stoppé ./gradlew build
$
El número entre corchetes`[1]`es elnúmero de trabajo. Le `+`indica el trabajo por defecto.
fg — Traer al primer plano
`fg`Lleva el trabajo suspendido al primer plano. El proceso continúa exactamente donde se había detenido.
$ fg
./gradlew build
> Building... (reprend où il en était)
Con un número de trabajo específico :
$ fg %2
bg — Reanudar en segundo plano
`bg`reanuda el proceso sin bloquear el terminal. Ideal para las builds largas.
$ bg
[1]+ ./gradlew build &
$
Le `&`al final significa que el proceso se ejecuta en segundo plano.
jobs — Listar los trabajos del shell
$ jobs
[1]- Stoppé vim README.md
[2]+ En cours ./gradlew build
@startuml skinparam backgroundColor #FEFEFE skinparam defaultFontName sans-serif state "Primer plano\n(terminal bloqué)" as fg #LightCoral state "Suspendido\n(Ctrl+Z)" as stopped #LightYellow state "Fondo\n(bg)" as bg_ #LightGreen [*] --> fg : Lance une commande fg --> stopped : Ctrl+Z\n(SIGTSTP) stopped --> fg : fg\nvuelve al primer plano stopped --> bg_ : bg\nse reanuda en segundo plano bg_ --> fg : fg\ntraer al frente fg --> [*] : Pedido completado note right of stopped El proceso está congelado pero _pas_ muerto end note note left of bg_ El terminal está libre el build continúa end note @enduml
Escenario 1: El build largo
Es el caso de uso más común. Ejecutas una compilación de Gradle, el terminal queda bloqueado y necesitas hacer otra cosa.
@startuml skinparam backgroundColor #FEFEFE autonumber actor Développeur as dev participant "Terminal" as term participant "Gradle" as gradle database "Estado\nproceso" as state dev -> term : ./gradlew construir term -> gradle : Lanza la build gradle -> state : En curso (FG) dev -> term : Ctrl+Z term -> state : Suspendido (trabajo [1]) term --> dev : Prompt libre $ dev -> term : git status term --> dev : árbol de trabajo limpio dev -> term : fg term -> state : Retoma (FG) gradle --> dev : Construcción exitosa ✓ note right of state El proceso Gradle nunca ha sido matado Continúa exactamente donde se había detenido end note @enduml
Paso a paso
$ ./gradlew build
> Building...
^Z
[1]+ Stoppé ./gradlew build
$ git status
On branch main
nothing to commit, working tree clean
$ fg
./gradlew build
> Building...
BUILD SUCCESSFUL in 2m 34s
Escenario 2: El editor olvidado
Estás en`vim`, necesitas consultar otro archivo sin salir`vim`.
# Dans vim, en mode commande :
:shell
$ cat /path/to/other/file.txt
$ exit
# Retour dans vim
Pero es pesado. Con`Ctrl+Z`, es inmediato :
# Dans vim, n'importe quel moment :
Ctrl+Z
[1]+ Stoppé vim README.md
$ cat /path/to/other/file.txt
# ... lire le fichier ...
$ fg
vim README.md
# Retour exact là où on en était, curseur en place
@startuml skinparam backgroundColor #FEFEFE autonumber actor Développeur as dev participant "vim" as vim participant "Shell" as shell dev -> vim : edición en curso dev -> vim : Ctrl+Z vim -> shell : Suspendido (job [1]) dev -> shell : cat autre_fichier.txt shell --> dev : contenido del archivo dev -> shell : fg shell -> vim : Reanuda (trabajo [1]) vim --> dev : Cursor exactamente\nen la misma posición note right of vim vim restaura intcompletamente el estado : posición del cursor, buffer, pila de deshacer end note @enduml
Escenario 3: El proceso opencode suspendido
Es el escenario que motivó este artículo. Usted utiliza`opencode`(herramienta CLI para controlar un LLM en tu código), y el proceso está suspendido.
@startuml skinparam backgroundColor #FEFEFE skinparam defaultFontName sans-serif skinparam componentStyle rectangle actor Développeur as dev participant "opencode\n(LLM agente)" as agent participant "Shell" as shell participant "git" as git dev -> agent : Session active agent -> agent : Tour de parole\ndu LLM en cours note over agent Ctrl+Z arrive en plein milieu d'une analyse de code end note dev -> agent : Ctrl+Z agent -> shell : Suspendu (job [1]) dev -> git : git diff git --> dev : changements visibles dev -> shell : fg shell -> agent : Reprend (job [1]) agent --> dev : Reprend exactement\nl'analyse en cours note right of agent Aucune perte de contexte Le LLM reprend sa réponse exactement où il en était end note @enduml
@startuml skinparam backgroundColor #FEFEFE skinparam defaultFontName sans-serif skinparam componentStyle rectangle actor Développeur as dev participant "opencode\n(LLM agent)" as agent participant "Shell" as shell participant "git" as git dev -> agent : Sesión activa agent -> agent : Tour de parole\ndu LLM en cours note over agent Ctrl+Z llega en medio de un análisis de código end note dev -> agent : Ctrl+Z agent -> shell : Suspendu (job [1]) dev -> git : git diff git --> dev : cambios visibles dev -> shell : fg shell -> agent : Retoma (trabajo [1]) agent --> dev : Reprend exactement\nl'analyse en cours note right of agent Ninguna pérdida de contexto El LLM retoma su respuesta exactamente donde estaba end note @enduml
La ventaja es doble:
-
Sin pérdida de contexto: la sesión LLM, el historial de conversación, los archivos abiertos — todo está preservado
-
Sin reinicio: no es necesario volver a ejecutar opencode, recargar el contexto, volver a explicar el problema al LLM
Escenario 4: Gestionar varios trabajos simultáneamente
fg et `bg`aceptan un número de trabajo para dirigirse a un proceso específico cuando varios están suspendidos.
$ vim config.yml
^Z
[1]+ Stoppé vim config.yml
$ ./gradlew test
^Z
[2]+ Stoppé ./gradlew test
$ htop
^Z
[3]+ Stoppé htop
$ jobs
[1] Stoppé vim config.yml
[2]- Stoppé ./gradlew test
[3]+ Stoppé htop
$ fg %2
./gradlew test
# Le build reprend en avant-plan
$ bg %3
[3] htop &
# htop reprend en arrière-plan
@startuml
skinparam backgroundColor #FEFEFE
rectangle "Trabajos suspendidos" as jobs #LightYellow {
card "[1] vim config.yml" as j1
card "[2] ./gradlew test" as j2
card "[3] htop" as j3
}
rectangle "Acciones" as actions #LightGreen {
card "fg %2\n→ primer plano" as a1
card "bg %3\n→ fondo" as a2
card "fg %1\n→ primer plano" as a3
}
jobs --> actions : fg/bg + numéro de job
actions --> j2 : Reprend
actions --> j3 : En arrière-plan
note bottom of jobs
Chaque job conserve
son état exact
entre les suspend/resume
end note
@enduml
@startuml
skinparam backgroundColor #FEFEFE
rectangle "Trabajos suspendidos" as jobs #LightYellow {
card "[1] vim config.yml" as j1
card "[2] ./gradlew prueba" as j2
card "[3] htop" as j3
}
rectangle "Acciones" as actions #LightGreen {
card "fg %2\n→ primer plano" as a1
card "bg %3\n→ fondo" as a2
card "fg %1\n→ primer plano" as a3
}
jobs --> actions : fg/bg + número del trabajo
actions --> j2 : Retoma
actions --> j3 : En segundo plano
note bottom of jobs
Cada trabajo conserva
su estado exacto
entre los suspend/resume
end note
@enduml
| Orden | Efecto | Ejemplo |
|---|---|---|
|
Suspenda el proceso en primer plano |
Envío de`SIGTSTP` |
|
Reanuda el trabajo predeterminado en primer plano |
|
|
Reanuda el trabajo n en primer plano |
|
|
Reanuda el trabajo predeterminado en segundo plano |
|
|
Reanuda el trabajo n en segundo plano |
|
|
Enumera los trabajos del shell actual |
|
|
Termina el trabajo n |
|
Diferencias entre fg, bg, Ctrl+Z, Ctrl+C y &
Muchos desarrolladores confunden estos mecanismos. Aquí tienes una aclaración decisiva.
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif
rectangle "**Ctrl+Z**\nSIGTSTP" as ctrlz #LightYellow {
card "Suspende el proceso\n(todavía está en memoria)\nUtilizable con fg/bg" as c1
}
rectangle "**Ctrl+C** \nSIGINT" as ctrlc #LightCoral {
card "Finaliza el proceso\n(sin posibilidad de retorno)\nPérdida de todo el estado" as c2
}
rectangle "** & \n(fondo)" as ampersand #LightGreen {
card "Inicia directamente\nen segundo plano\nTerminal libre inmediatamente" as c3
}
rectangle "**fg**\n(primer plano)" as fg_ #SkyBlue {
card "Trae un trabajo\nsuspendido en primer plano\nTerminal ocupado" as c4
}
rectangle "**bg**\n(fondo)" as bg_ #Lavender {
card "Reanuda un trabajo\nsuspendido en segundo plano\nTerminal libre" as c5
}
ctrlz -right-> fg_ : fg pour reprendre
ctrlz -right-> bg_ : bg pour continuer\nen arrière-plan
ctrlc -right-> c2 : Pas de retour\nprocessus tué
note bottom of ctrlz
Le processus est **figé**
mais **pas tué**
end note
note bottom of ampersand
Alternative : lancer
./gradlew build &
directement en arrière-plan
end note
@enduml
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif
rectangle "**Ctrl+Z**\nSIGTSTP" as ctrlz #LightYellow {
card "Pausa el proceso\n(il est toujours en mémoire)\nUtilisable con fg/bg" as c1
}
rectangle "**Ctrl+C**\nSIGINT" as ctrlc #LightCoral {
card "Mate el proceso\n(pas de retour possible)\nPerte de todo el estado" as c2
}
rectangle "**& **\n(arrière-plan)" as ampersand #LightGreen {
card "Ejecutar directamente\n\en fondo\nTerminal libre inmediatamente" as c3
}
rectangle "**fg**\n(foreground)" as fg_ #SkyBlue {
card "Trae un trabajo\nsuspendido en primer plano\nTerminal ocupado" as c4
}
rectangle "**bg**\n(background)" as bg_ #Lavender {
card "Retoma un trabajo\nsuspendido en segundo plano\nTerminal libre" as c5
}
ctrlz -right-> fg_ : fg para retomar
ctrlz -right-> bg_ : bg para continuar\nen segundo plano
ctrlc -right-> c2 : No retorno\nproceso terminado
note bottom of ctrlz
El proceso está **congelado** pero **no matado**
end note
note bottom of ampersand
Alternativa : lanzar
./gradlew build &
directamente en segundo plano
end note
@enduml
Ctrl+Z`esno destructivo. El proceso está congelado tal cual, en memoria. Puede continuar inmediatamente con`fg. Es un pause, no un stop.
|
El ciclo de vida completo de un trabajo
@startuml skinparam backgroundColor #FEFEFE skinparam defaultFontName sans-serif title Ciclo de vida completo de un trabajo shell state "Inexistente" as none state "Primer plano\n(ocupa la terminal)" as foreground #LightCoral state "Suspendido\n(Ctrl+Z / SIGTSTP)" as suspended #LightYellow state "Fondo\n(bg o &)" as background #LightGreen state "Terminado\n(exit code 0)" as done #LightGray [*] --> none none --> foreground : tape une commande foreground --> suspended : Ctrl+Z foreground --> done : fin normale suspended --> foreground : fg suspended --> background : bg suspended --> done : kill %n background --> foreground : fg background --> done : fin normale\n(en arrière-plan) background --> suspended : Ctrl+Z\n(si fg puis Ctrl+Z) done --> [*] note right of suspended L'état suspendu est le pivot de tout le système de jobs end note @enduml
@startuml skinparam backgroundColor #FEFEFE skinparam defaultFontName sans-serif title Ciclo de vida completo de un trabajo shell state "No existe" as none state "Primer plano\n(occupe le terminal)" as foreground #LightCoral state "Suspendido\n(Ctrl+Z / SIGTSTP)" as suspended #LightYellow state "Segundo plano\n(bg ou &)" as background #LightGreen state "Terminado\n(exit code 0)" as done #LightGray [*] --> none none --> foreground : Escribe un comando foreground --> suspended : Ctrl+Z foreground --> done : fin normal suspended --> foreground : fg suspended --> background : bg suspended --> done : matar %n background --> foreground : fg background --> done : final normal\n(en arrière-plan) background --> suspended : Ctrl+Z\n(si fg puis Ctrl+Z) done --> [*] note right of suspended El estado suspendido es el pivote de todo el sistema de trabajos end note @enduml
fg con el trabajo más reciente y la alternancia
fg`Sin argumento trae el trabajo marcado.+(el más reciente). Pero también puedes usar%-`Para apuntar al trabajo anterior
$ vim file1.txt
^Z
[1]+ Stoppé vim file1.txt
$ vim file2.txt
^Z
[2]+ Stoppé vim file2.txt
$ fg # ramène job [2] (le plus récent)
$ fg %- # ramène job [1] (le précédent)
matar un trabajo de forma limpia
$ jobs
[1]- Stoppé vim config.yml
[2]+ Stoppé ./gradlew test
$ kill %2 # envoie SIGTERM au job 2
$ kill -9 %1 # envoie SIGKILL au job 1 (force)
désown : desanclar del shell
disown`Elimina un trabajo de la tabla de trabajos del shell. El proceso sigue ejecutándose pero ya no puede ser recuperado con`fg :
$ ./gradlew build &
[1] 12345
$ disown %1
# Le processus continue mais n'est plus lié au shell
# Ça survives à la fermeture du terminal
Combinar con nohup para procesos largos
Para que un proceso sobreviva al cierre del terminal :
$ nohup ./gradlew build &
[1] 12345
$ disown %1
# Le build continue même si vous fermez le terminal
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif
rectangle "fg" as fg_ #SkyBlue {
card "Trae el trabajo\nel más reciente (+)" as f1
card "Apunta a un trabajo\nespecífico : fg %n" as f2
card "Alterna : fg %-" as f3
}
rectangle "matar %n" as kill_ #LightCoral {
card "SIGTERM (limpio)" as k1
card "SIGKILL -9 (fuerza)" as k2
}
rectangle "renegar" as disown #Lavender {
card "Desvincular del shell\n(sobrevive a la desconexión)" as d1
}
rectangle "nohup + &" as nohup_ #LightGreen {
card "Proceso inmunizado\ncontra SIGHUP\n(sobrevive al cierre\ndel terminal)" as n1
}
fg_ -right-> kill_ : si faut\nterminer
kill_ -right-> disown_ : ou détacher
nohup_ -left-> fg_ : fg ramène en\navant-plan
note bottom of disown_
Après disown, fg ne peut
plus ramener le job
end note
@enduml
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif
rectangle "fg" as fg_ #SkyBlue {
card "Trae el trabajo\nel más reciente (+)" as f1
card "Apunta a un trabajo\nespecífico : fg %n" as f2
card "Alternar : fg %-" as f3
}
rectangle "matar %n" as kill_ #LightCoral {
card "SIGTERM (limpio)" as k1
card "SIGKILL -9 (fuerza)" as k2
}
rectangle "disown" as disown #Lavender {
card "Desasociar del shell\n(survit à la déconnexion)" as d1
}
rectangle "nohup + &" as nohup_ #LightGreen {
card "Proceso inmune\ncontra SIGHUP\n(survit à la fermeture\ndu terminal)" as n1
}
fg_ -right-> kill_ : si hay que\nterminar
kill_ -right-> disown_ : o desmanchar
nohup_ -left-> fg_ : fg lleva al primer plano
note bottom of disown_
Después de disown, fg no puede
más recuperar el trabajo
end note
@enduml
Confundir Ctrl+Z y Ctrl+C
Es el error más frecuente.`Ctrl+C`mata el proceso.`Ctrl+Z`lo suspende. Si lo presiona`Ctrl+C`por reflejo, todo el estado se pierde — archivos abiertos, sesiones LLM, builds en curso.
@startuml
skinparam backgroundColor #FEFEFE
rectangle "Ctrl+Z (SIGTSTP)" as z #LightGreen {
card "Proceso congelado en memoria" as z1
card "lo devuelve intacto" as z2
card "ninguna pérdida" as z3
}
rectangle "Ctrl+C (SIGINT)" as c #LightCoral {
card "Proceso terminado" as c1
card "Estado perdido definitivamente" as c2
card "No es posible volver" as c3
}
note bottom of z
Pause → Reprendre
end note
note bottom of c
Kill → Perdu
end note
@enduml
@startuml
skinparam backgroundColor #FEFEFE
rectangle "Ctrl+Z (SIGTSTP)" as z #LightGreen {
card "Proceso congelado en memoria" as z1
card "fg lo devuelve intacto" as z2
card "Sin pérdida" as z3
}
rectangle "Ctrl+C (SIGINT)" as c #LightCoral {
card "Proceso terminado" as c1
card "Estado perdido definitivamente" as c2
card "Retorno imposible" as c3
}
note bottom of z
Pausa → Continuar
end note
note bottom of c
Kill → Perdido
end note
@enduml
jobs, fg et `bg`solo funcionan en el shell que lanzó los procesos. Si abre un nuevo terminal, no verá los trabajos del otro.
# Terminal 1
$ vim file.txt
^Z
[1]+ Stoppé vim file.txt
# Terminal 2 (nouveau)
$ jobs
# (rien — les jobs sont locaux au shell)
Para ver los procesos system-wide, utilice`ps` ou htop:
ps aux | grep vim
Los trabajos no sobreviven al cierre del shell
Si cierras el terminal, todos los trabajos suspendidos o en segundo plano son destruidos. Para que un proceso sobreviva, utilice`nohup`+disown:
$ nohup ./gradlew build &
[1] 12345
$ disown %1
# Fermer le terminal → le build continue
Los procesos interactivos y fg
Algunos programas interactivos no funcionan bien después de un`Ctrl+Z`+fg. Es raro pero ocurre :
-
Algunos programas que utilizan señales (vim, htop, less manejan bien`Ctrl+Z`)
-
Los programas de red de larga duración (ssh, opencode) generalmente se recuperan correctamente
-
Los programas que modifican el terminal (ncurses) pueden a veces dejar el terminal en un estado inesperado
En caso de terminal corrupto después de un`fg`, escriba :
reset
Diagrama resumido
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif
skinparam ArrowColor #444444
title "fg — El consejo que cambia todo"
rectangle "Problema" as problem #LightCoral {
card "Terminal bloqueado\npor un proceso" as p1
card "Abrir un nuevo\nterminal = solución pesada" as p2
}
rectangle "**Solución**" as solution #LightGreen {
card "Ctrl+Z → suspender" as s1
card "fg → retoma" as s2
card "bg → en segundo plano" as s3
card "jobs → ver los suspendidos" as s4
}
rectangle "Ventajas" as advantages #SkyBlue {
card "Sin pérdida de contexto" as a1
card "No reinicio" as a2
card "Un solo terminal basta" as a3
}
problem -right-> solution : "La solución nativa\nUnix desde hace 40 años"
solution -right-> advantages : "Resultado"
note bottom of advantages
fg n'est pas un tips obscur
C'est un mécanisme fondamental
du shell Unix
end note
@enduml
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif
skinparam ArrowColor #444444
title "fg — El consejo que cambia todo"
rectangle "**Problema**" as problem #LightCoral {
card "Terminal bloqueado\npor un proceso" as p1
card "Abrir un nuevo\nterminal = solución pesada" as p2
}
rectangle "**Solución**" as solution #LightGreen {
card "Ctrl+Z → suspender" as s1
card "fg → reanudar" as s2
card "bg → en segundo plano" as s3
card "jobs → ver los suspendidos" as s4
}
rectangle "**Ventajas**" as advantages #SkyBlue {
card "No hay pérdida de contexto" as a1
card "No hay reinicio" as a2
card "Un solo terminal basta" as a3
}
problem -right-> solution : "La solución nativa\nUnix desde hace 40 años"
solution -right-> advantages : "Resultado"
note bottom of advantages
fg no es un consejo oscuro
Es un mecanismo fundamental
del shell Unix
end note
@enduml
La mayoría de los desarrolladores modernos descubren`fg`tarde, o incluso nunca. Algunas razones :
-
Los IDE ocultan la terminal: VS Code ofrece un terminal integrado, pero las pestañas múltiples hacen`fg`menos necesario en apariencia
-
Las herramientas gráficas reemplazan a la CLI: los gestores de archivos, los monitores del sistema, los clientes gráficos de Git
-
tmux y screen: estos multiplexores resuelven el mismo problema de manera diferente, pero`fg`es más simple y siempre disponible
Pero,`fg`es :
-
universal: presente en todos los shells POSIX (bash, zsh, fish…)
-
Sin dependencia: no es necesario instalar tmux o screen
-
Instantáneo: dos golpes (
Ctrl+Z`luego`fg) para suspender y reanudar -
**Preservador de contexto
Wait that’s wrong: Should be "Preservador de contexto". Let’s output exactly that.
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif
rectangle "¿Por qué fg es\nsubestimado?" as why #LightCoral {
card "IDE con terminal\npestañas múltiples" as w1
card "Herramientas gráficas\nque reemplazan el CLI" as w2
card "tmux/screen\nresuelven el problema\nde otra forma" as w3
}
rectangle "¿Por qué fg es\nsuperior?" as superior #LightGreen {
card "Universal :\nbash,\nzsh,\nfish,\nsh..." as s1
card "Sin dependencia :\nsin instalación" as s2
card "Dos pulsaciones :\n\nCtrl+Z luego fg" as s3
card "Contexto preservado :\ncero pérdida de estado" as s4
}
why -right-> superior : "La simplicidad\nsiempre gana"
@enduml
Preservador de contexto**: el estado del proceso está intacto
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif
rectangle "¿Por qué fg está\nsubestimado?" as why #LightCoral {
card "IDE con terminal\nmultipestañas" as w1
card "Herramientas gráficas\nque sustituyen la CLI" as w2
card "tmux/screen\nresuelven el problema\nde otra manera" as w3
}
rectangle "¿Por qué fg es\nsuperior?" as superior #LightGreen {
card "Universal: bash,\nzsh, fish, sh..." as s1
card "Sin dependencia:\nSin instalación" as s2
card "Dos pulsaciones:\nCtrl+Z luego fg" as s3
card "Contexto preservado:\ncero pérdida de estado" as s4
}
why -right-> superior : "La simplicidad\nsiempre gana"
@enduml
Memoria técnica: las señales
Para los curiosos, aquí están las señales implicadas:
@startuml skinparam backgroundColor #FEFEFE skinparam defaultFontName sans-serif participant "Usuario" as user participant "Shell" as shell participant "Proceso" as proc user -> shell : Ctrl+Z shell -> proc : SIGTSTP (señal 18) note right of proc : Proceso bloqueado\nen memoria user -> shell : fg shell -> proc : SIGCONT (señal 19) note right of proc : Proceso reanuda\nen primer plano user -> shell : bg shell -> proc : SIGCONT (señal 19) note right of proc : El proceso se reanuda\nen segundo plano user -> shell : Ctrl+C shell -> proc : SIGINT (señal 2) note right of proc : Proceso terminado\nestado perdido @enduml
El flujo completo:
@startuml skinparam backgroundColor #FEFEFE skinparam defaultFontName sans-serif participant "Usuario" as user participant "cáscara" as shell participant "Proceso" as proc user -> shell : Ctrl+Z shell -> proc : SIGTSTP (signal 18) note right of proc : Processus figé\nen mémoire user -> shell : fg shell -> proc : SIGCONT (signal 19) note right of proc : Processus reprend\nen avant-plan user -> shell : bg shell -> proc : SIGCONT (signal 19) note right of proc : Processus reprend\nen arrière-plan user -> shell : Ctrl+C shell -> proc : SIGINT (signal 2) note right of proc : Processus terminé\nétat perdu @enduml
Conclusión
`fg`No es un consejo oscuro — es un mecanismo fundamental del shell Unix, disponible desde los años 70. El hecho de que la mayoría de los desarrolladores lo ignoren es un síntoma de nuestra época: los IDE y los multiplexores nos han alejado de lo básico.
Pero cuando estás en un servidor SSH, en una terminal mínima, o simplemente estás utilizando`opencode`y que el LLM está en pleno trabajo —Ctrl+Z, fg, bg, `jobs`son tus mejores amigos.
_ Ctrl+Z suspend, fg reanuda. Es la pausa-reproducción del terminal. _