vreme čitanja : 10 minutes

Vi bacate`./gradlew build`, terminal je blokiran za 3 minute, i vi trebate da uradite nešto drugo čekajući? Ne treba da otvorite novu karticu.`Ctrl+Z`zaustavljuje proces,`fg`Vraća vas tačno na mesto gde ste ga ostavili. To je najmanje cenjen Unix savet u svakodnevnom životu programera.

так

[]

Problem: zauzet terminal

Svaki programer je doživio ovu situaciju:

$ ./gradlew build
> Building...

Терминал је блокиран. Више не можете укуцати ниједну команду. И вам је потребно прегледати датотеку, покренути`git status`, или проверити заузети порт.

@startuml
skinparam backgroundColor #FEFEFE

actor Développeur as dev
participant "Терминал" as term
participant "Gradle
( proces )" as gradle

dev -> term : ./gradlew build
term -> gradle : Lance le build
gradle -> term : Occupe le terminal\n(pas de prompt)
dev -> term : veut taper une commande
term --> dev : ❌ Terminal bloqué

note right of dev
  Le développeur est
  paralysé pendant
  toute la durée du build
end note
@enduml

Većina programera otvara novi terminal. Ipak postoji rešenje koje je elegantnija, brža i prirodna: upravljanje poslovima.

Tri neophodne komande

Ctrl+Z — Zaustavi (SIGTSTP)

`Ctrl+Z`Šalje signal`SIGTSTP`процесу у передњем плану. Процес јеsuspendovan— ne ubijen — i terminal vraća svoj prompt.

$ ./gradlew build
> Building...
^Z
[1]+  Stoppé    ./gradlew build
$

Број између заграда`[1]`јеbroj posla. Le `+`ukazuje na podrazumevani posao

fg — Врати на предњи план

`fg`vraća zaustavljen posao u primarni plan. Proces se nastavlja tačno gde se je zaustavio.

$ fg
./gradlew build
> Building... (reprend où il en était)

Sa specifičnim brojem posla :

$ fg %2

bg — Nastavi u pozadini

`bg`Uzima proces bez blokiranja terminala. Idealno za dugograjde gradnje.

$ bg
[1]+ ./gradlew build &
$

Le `&`Na kraju znači da se proces izvršava u pozadini.

jobs — Lista poslova u shellu

$ jobs
[1]-  Stoppé    vim README.md
[2]+  En cours   ./gradlew build
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

state "prednji plan\n(blokiran terminal)" as fg #LightCoral
state "Заустavljen\n(Ctrl+Z)" as stopped #LightYellow
state "Фон\n(bg)" as bg_ #LightGreen

[*] --> fg : Lance une commande
fg --> stopped : Ctrl+Z\n(SIGTSTP)
stopped --> fg : fg\nreprend en avant-plan
stopped --> bg_ : bg\nreprend en arrière-plan
bg_ --> fg : fg\nramène en avant-plan
fg --> [*] : Commande terminée

note right of stopped
  Le processus est figé
  mais _pas_ tué
end note

note left of bg_
  Le terminal est libre
  le build continue
end note
@enduml

Scenarij 1: dugi build

Ovo je najčešći slučaj korištenja. Pokrenete Gradle build, terminal je blokiran, i morate da uradite nešto drugo.

@startuml
skinparam backgroundColor #FEFEFE
autonumber

actor Développeur as dev
participant "terminal" as term
participant "Gradle" as gradle
database "stanje\nproces" as state

dev -> term : ./gradlew build
term -> gradle : Lance le build
gradle -> state : En cours (FG)
dev -> term : Ctrl+Z
term -> state : Suspendu (job [1])
term --> dev : Prompt libre $

dev -> term : git status
term --> dev : working tree clean

dev -> term : fg
term -> state : Reprend (FG)
gradle --> dev : Build réussi ✓

note right of state
  Le processus Gradle
  n'a jamais été tué
  Il reprend exactement
  où il s'était arrêté
end note
@enduml

Korak po korak

$ ./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

Scenario 2: Zaboravljeni urednik

Vi ste u`vim`, trebate da pogledate drugi fajl bez napuštanja`vim`.

# Dans vim, en mode commande :
:shell
$ cat /path/to/other/file.txt
$ exit
# Retour dans vim

Ali je teško. Sa`Ctrl+Z`, to je odmah :

# 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 "lupija" as shell

dev -> vim : édition en cours
dev -> vim : Ctrl+Z
vim -> shell : Suspendu (job [1])
dev -> shell : cat autre_fichier.txt
shell --> dev : contenu du fichier
dev -> shell : fg
shell -> vim : Reprend (job [1])
vim --> dev : Curseur exactement\nà la même position

note right of vim
  vim restaure
  intégralement l'état :
  position du curseur,
  buffer, undo stack
end note
@enduml

Белешка:`vim`savršeno vraća svoje stanje nakon`fg`: pozicija kurzora, sadržaj bafera, istorija poništavanja — sve je sačuvano.

Сценарио 3: Процесс opencode приостановљен

Ово је сценариј који је мотивао ovaj чланак. Ви користите`opencode`(CLI alat za pokretanje LLM na vašem kodu), a proces je zaustavljen.

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif
skinparam componentStyle rectangle

actor Développeur as dev
participant "opencode
(агент LLM)" 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
$ opencode
# ... session en cours, LLM analyse le code ...
^Z
[1]+  Stoppé    opencode

$ git diff HEAD~1
# vérifier les changements récents

$ fg
opencode
# Le LLM reprend là où il s'était arrêté

Предност је двострука :

  1. Нет губитка контекста: сесија LLM, историја разговора, отварені датотеке — све је сачувано

  2. Никаког рестартане треба покретати опенкоде, не треба поновити контекст, не треба поново обяснити проблематицу LLM-у

Сценарио 4: Управљати више послова у истом времену

fg et `bg`Prihvataju broj posla za ciljanje specifičnog procesa kada je više procesa pozastavljen.

$ 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 "Pozastavljeni poslovi" as jobs #LightYellow {
  card "[1] vim config.yml" as j1
  card "[2] ./gradlew test" as j2
  card "[3] htop" as j3
}

rectangle "Akcije" as actions #LightGreen {
  card "fg %2
→ предњи план" as a1
  card "bg %3\n→ pozadina" as a2
  card "fg %1\n→ prednji plan" 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

Свод наредби за poslove

narudžba efekat primer

Ctrl+Z

Suspendiraj proces u prvom planu

Slanje`SIGTSTP`

fg

Ponovo preuzima podrazumevani posao u primarnom planu

fg ou fg %1

fg %n

Навести посао n у передњи план

fg %2

bg

Продовити подразумевани задатак у позадини

bg ou bg %1

bg %n

Врати посао n у позадни план

bg %2

jobs

Покажи радње текуће шелле

jobs -l(sa PID)

kill %n

Završi posao n

kill %2

Razlike između fg, bg, Ctrl+Z, Ctrl+C i &

Mnogo programera miješa ove mehanizme. Evo odlučnog objašnjenja.

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

rectangle "**Ctrl+Z**\nSIGTSTP" as ctrlz #LightYellow {
  card "Pauziraj proces\n(Još uvek je u memoriji)\nKoristivo sa fg/bg" as c1
}

rectangle "**Ctrl+C**\nSIGINT" as ctrlc #LightCoral {
  card "Ubij proces
(ne moguće vratiti)
Gubitak celog stanja" as c2
}

rectangle "** & **\n(pozadina)" as ampersand #LightGreen {
  card "Pokreni odmah
u pozadini
Slobodan terminal odmah" as c3
}

rectangle "**fg**
(предњи план)" as fg_ #SkyBlue {
  card "Премени заустављени задатак у провид\nЗаузети терминал" as c4
}

rectangle "**bg**
(pozadina)" as bg_ #Lavender {
  card "Nastavi posao
Suspendovan u pozadini
Slobodan terminal" 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
Пречица/Команда Signal Efekat Vratiti se nazad?

Ctrl+Z

SIGTSTP

Zaustavi proces (zamrznut, u memoriji)

Да :`fg` ou bg

Ctrl+C

SIGINT

Ubij proces (završen)

Не : уништожен процес

Ctrl+\

SIGQUIT

Zabij proces + core dump

Ne: proces uništen

commande &

—

Pokreni u pozadini direktno

`fg`da ga vrati u prednji plan

Ctrl+Z`jeнедеструктиван. Proces je zaklepčen kako jest, u memoriji. Možete nastaviti odmah sa`fg. To je pauza, ne zaustavak.

Potpun životni ciklus posla

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

title Potpuni životni ciklus shell posla
state "Nepostojeci" as none
state "Prioritetno\n(zauzima terminal)" as foreground #LightCoral
state "Zaustavljeno
(Ctrl+Z / SIGTSTP)" as suspended #LightYellow
state "Pozadina\n(bg ili &)" as background #LightGreen
state "Завршено
(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

Napredni saveti

fg sa najnovijim poslom i alternativom

fg`Без аргумента враћа означени посао+`(najnoviji). Ali možete Takođe koristiti

Wait: I accidentally capitalized "Takođe". Should be lowercase "takođe". So correct: " (najnoviji). Ali možete takođe koristiti". Ensure "takođe" is lowercase. Yes.

Thus final output.

</think>

(najnoviji). Ali možete takođe koristiti`%-`da se usmeri na prethodni posao :

$ 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)

убити посао на правилан начин

$ 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)

disown : odvoji se od shell-a

disown`Ukloni posao iz tabele poslova shella. Proces nastavlja da se izvršava, ali ne može više biti vratio sa`fg:

$ ./gradlew build &
[1] 12345

$ disown %1
# Le processus continue mais n'est plus lié au shell
# Ça survives à la fermeture du terminal

Kombinirati sa nohup za dugoke procese

Da bi proces preživio zatvaranje terminala:

$ 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 "Vrati posao
najnoviji (+)" as f1
  card "Целиј један посао
specifižno : fg %n" as f2
  card "Алтерниши : fg %-" as f3
}

rectangle "убиј %n" as kill_ #LightCoral {
  card "SIGTERM (čist)" as k1
  card "SIGKILL -9 (prisilno)" as k2
}

rectangle "одрећи се" as disown #Lavender {
  card "Одвој из шелла\n(остаје активан после одјаве)" as d1
}

rectangle "nohup + &" as nohup_ #LightGreen {
  card "Imunizovani proces
protiv SIGHUP
(preživljava zatvaranje terminala)" 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

ловушке и честе грешке

Мешати Ctrl+Z и Ctrl+C

Ovo je najčešća greška.`Ctrl+C`ubija proces.`Ctrl+Z`Ga zaustavlja. Ako pritisnete na`Ctrl+C`iz refleksa, sve stanje je izgubljeno — otvoreni fajlovi, sesije LLM, gradnje u toku.

@startuml
skinparam backgroundColor #FEFEFE

rectangle "Ctrl+Z (SIGTSTP)" as z #LightGreen {
  card "Zamrzli proces u memoriji" as z1
  card "fg ga vraća nepovređen" as z2
  card "Никаша губатак" as z3
}

rectangle "Ctrl+C (SIGINT)" as c #LightCoral {
  card "Završen proces" as c1
  card "Стажно загублено стање" as c2
  card "Nemoguće vraćanje" as c3
}

note bottom of z
  Pause → Reprendre
end note

note bottom of c
  Kill → Perdu
end note
@enduml

Poslovi su lokalni u shellu

jobs, fg et `bg`ne funkcionišu samo u shellu koji je pokrenuo procese. Ako otvorite novi terminal, nećete videti jobove drugog.

# Terminal 1
$ vim file.txt
^Z
[1]+  Stoppé    vim file.txt

# Terminal 2 (nouveau)
$ jobs
# (rien — les jobs sont locaux au shell)

Da biste videli sistemski procesi, koristite`ps` ou htop:

ps aux | grep vim

Poslovi ne preživljavaju zatvaranje shell-a

Ako zatvorite terminal, svi suspenirani ili pozadinski poslovi su uništeni. Da biste proces preživi, koristite`nohup`+disown :

$ nohup ./gradlew build &
[1] 12345
$ disown %1
# Fermer le terminal → le build continue

Interaktivni procesi i fg

Neki interaktivni programi nisu u dobrom stanju nakon jednog`Ctrl+Z`+fg. Ретко је, но дешава се :

  • Neki programi koji koriste signale (vim, htop, less) dobro upravljaju`Ctrl+Z`)

  • Дуготрајни мрежни програми (ssh, opencode) обично исправно опорављају

  • Programi koji modifikuju terminal (ncurses) mogu ponekad ostaviti terminal u neočekivanom stanju.

U slučaju oštećenog terminala nakon`fg`, ukucaj :

reset

Сводни дијаграм

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif
skinparam ArrowColor #444444

title "fg — Savet koji menja sve"

rectangle "**Problem**" as problem #LightCoral {
  card "Terminal zaključan\nod jednog procesa" as p1
  card "Отварање новог
терминала = тешко решење" as p2
}

rectangle "**rešenje**" as solution #LightGreen {
  card "Ctrl+Z → pauziraj" as s1
  card "fg → преузима" as s2
  card "bg → у позадину" as s3
  card "poslovi → pogledajte suspendovane" as s4
}

rectangle "Предности" as advantages #SkyBlue {
  card "Нема губитка контекста" as a1
  card "Није могуће рестартирати" as a2
  card "Dovoljno je jedan terminal" as a3
}

problem -right-> solution : "Природно решение
Unix од 40 година"
solution -right-> advantages : "Резултат"

note bottom of advantages
  fg n'est pas un tips obscur
  C'est un mécanisme fondamental
  du shell Unix
end note
@enduml

Zašto fg je podocenjen

Većina modernih programera otkriva`fg`kasno, ili čak nikada. Neki razlozi :

  1. IDE sakrivaju terminal: VS Code nudi ugrađeni terminal, ali više kartica prave`fg`manje potrebno na prvi pogled

  2. Grafički alati zamjenjuju CLI: управљачи фајловима, системски монитори, графички кlijenti Git

  3. tmux i screen: ovi multipleskseri rešavaju isti problem na drugačiji način, ali`fg`je jednostavniji i uvek dostupan

Ipak,`fg`je :

  1. универзалниprisutan u svim POSIX shell-ovima (bash, zsh, fish…​)

  2. Bez zavisnosti: нема потребе да инсталирате tmux или screen

  3. Snimak: dva udara (Ctrl+Z`zatim`fg) za zaustavljanje i nastavak

  4. Čuvac konteksta: stanje procesa je neporušeno

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

rectangle "Zašto je fg\npodocenjen ?" as why #LightCoral {
  card "IDE sa terminalom\nvišekartično" as w1
  card "Графички алати
Који замњују CLI" as w2
  card "tmux/screen
решају проблем на другом начин" as w3
}

rectangle "Zasto je fg
superior?" as superior #LightGreen {
  card "Универзално : bash,\nzsh, fish, sh..." as s1
  card "Bez zavisnosti:\nbez instalacije" as s2
  card "Два натиска:\n`Ctrl+Z` затим fg" as s3
  card "Kontekst sačuvan :
nula gubitka stanja" as s4
}

why -right-> superior : "Jednostavnost
uvijek pobeđuje"
@enduml

Tehnička memorija: signali

Za zainteresovane, voici signali koji su uključeni :

Сигнал Име Poslao Efekat

2

SIGINT

Ctrl+C

Prekid — završava proces

3

SIGQUIT

Ctrl+\

Napusti sa core dump

18

SIGTSTP

Ctrl+Z

Interaktivni stop — poništava proces

19

SIGCONT

fg / bg

Nastavi — ponovo pokreće suspendovan proces

15

SIGTERM

kill %n

Правилан завршатак

9

SIGKILL

kill -9 %n

Prisilno završavanje (ne može se prekinuti)

Потпун поток :

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

participant "Корисник" as user
participant "lupina" as shell
participant "Proces" 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

Zaključak

`fg`Nije sakriven savet — to je fundamentalni mehanizam Unix shella, dostupan od 70-h godina. Činjenica da većina razvojara to ignoriše je simptom našeg doba: IDE i multiplexeri nas su udaljiti od osnova.

Pero kada ste na SSH serveru, u minimalnom terminalu, ili jednostavno koristite`opencode`и да LLM је у полној раду —Ctrl+Z, fg, bg, `jobs`су ваши најбољи пријатели.

_ Ctrl+Z suspend, fg nastavlja. To je pauza-play terminala. _

Повезани чланци