waktu membaca : 10 minutes

Anda melempar`./gradlew build`, terminal terblokir selama 3 menit, dan Anda perlu melakukan sesuatu yang lain menunggu ? Tidak perlu membuka tab baru.`Ctrl+Z`menangguhkan proses,`fg`Dia mengembalikannya tepat di tempat Anda meninggalkan. Ini adalah tips Unix yang paling kurang dihargai dalam kehidupan sehari-hari seorang pengembang.

toc

[]

Masalah: terminal yang sibuk

Setiap developer telah menjalani situasi ini:

$ ./gradlew build
> Building...

Terminal terblokir. Anda tidak dapat lagi mengetik perintah apa pun. Dan Anda perlu melihat sebuah file, menjalankan sebuah`git status`, atau memeriksa port yang sedang digunakan.

@startuml
skinparam backgroundColor #FEFEFE

actor Développeur as dev
participant "Terminal" as term
participant "Gradle\n( proses )" 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

Kebanyakan pengembang membuka terminal baru. Namun ada solusi yang lebih elegan, lebih cepat, dan bawaan: manajemen pekerjaan.

tiga perintah esensial

Ctrl+Z — Menangguhkan (SIGTSTP)

`Ctrl+Z`mengirim sinyal`SIGTSTP`ke proses latar depan. Prosesnya adalahditangguhkan— tidak terbunuh — dan terminal kembali mendapatkan prompt-nya.

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

Angka di antara tanda kurung`[1]`adalahnomor pekerjaan. Le `+`menunjukkan pekerjaan default

fg — Membawa ke depan

`fg`Memulihkan job yang dijeda ke latar depan. Proses melanjutkan tepat dari tempat ia berhenti.

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

Dengan nomor pekerjaan spesifik:

$ fg %2

bg — Lanjutkan di latar belakang

`bg`lanjutkan proses tanpa memblokir terminal. Ideal untuk build yang panjang.

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

Le `&`pada akhirnya berarti bahwa proses berjalan di latar belakang.

jobs — Daftar pekerjaan shell

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

state "Depan
(terminal diblokir)" as fg #LightCoral
state "Ditangguhkan\n(Ctrl+Z)" as stopped #LightYellow
state "Latar belakang\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

Skenario 1: Build yang panjang

Ini adalah kasus penggunaan yang paling umum. Anda menjalankan build Gradle, terminal terblokir, dan Anda perlu melakukan hal lain.

@startuml
skinparam backgroundColor #FEFEFE
autonumber

actor Développeur as dev
participant "Terminal" as term
participant "Gradle" as gradle
database "kondisi
proses" 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

langkah demi langkah

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

Skenario 2: editor yang dilapkan

Anda berada di`vim`, Anda perlu membuka file lain tanpa meninggalkan`vim`.

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

Tetapi ini berat. Dengan`Ctrl+Z`, ini langsung :

# 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 "semangat" as vim
participant "Kerang" 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

</think> </think> (No content to translate)vim`mengembalikan dengan sempurna keadaan setelah sebuah`fg: posisi kursor, isi buffer, riwayat pembatalan — semua dipertahankan.

Scenario 3 : Proses opencode ditangguhkan

Ini adalah skenario yang memotivasi artikel ini. Anda menggunakan`opencode`(alat CLI untuk mengendalikan LLM pada kode Anda), dan prosesnya ditangguhkan.

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

actor Développeur as dev
participant "opcode\n(agen 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é

Keuntungannya adalah ganda:

  1. Tidak ada kehilangan konteks: sesi LLM, riwayat percakapan, file yang terbuka — semuanya dipertahankan

  2. Tidak ada restart: tidak perlu menjalankan ulang opencode, tidak perlu memuat ulang konteks, tidak perlu menjelaskan ulang masalah kepada LLM

Skenario 4: Mengelola beberapa pekerjaan secara bersamaan

fg et `bg`Menerima nomor pekerjaan untuk menargetkan proses tertentu ketika beberapa proses ditangguhkan.

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

rectangle "Tindakan" as actions #LightGreen {
  card "fg %2\n→ latar depan" as a1
  card "bg %3\n→ arrière-plan" as a2
  card "fg %1\n→ latar depan" 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

Ringkasan perintah pekerjaan

Pesanana Efek Contoh

Ctrl+Z

Jeda proses latar depan

Pengiriman`SIGTSTP`

fg

Mengambil kembali pekerjaan default ke latar depan

fg ou fg %1

fg %n

Lanjutkan pekerjaan n di latar depan

fg %2

bg

Melanjutkan job default di latar belakang

bg ou bg %1

bg %n

Meneruskan pekerjaan n di latar belakang

bg %2

jobs

Daftar pekerjaan shell saat ini

jobs -l(dengan PID)

kill %n

Selesaikan pekerjaan n

kill %2

Perbedaan antara fg, bg, Ctrl+Z, Ctrl+C dan &

Banyak pengembang bingung dengan mekanisme ini. Ini adalah penjelasan yang penting.

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

rectangle "**Ctrl+Z**\nSIGTSTP" as ctrlz #LightYellow {
  card "Menjeda proses
(masih berada di memori)
Dapat digunakan dengan fg/bg" as c1
}

rectangle "**Ctrl+C**\nSIGINT" as ctrlc #LightCoral {
  card "Bunuh proses
(Tidak ada kemungkinan kembali)
Kehilangan seluruh status" as c2
}

rectangle "**& **
(latar belakang)" as ampersand #LightGreen {
  card "Mulai langsung
di latar belakang
Terminal gratis segera" as c3
}

rectangle "**fg**
(lat depan)" as fg_ #SkyBlue {
  card "Bawa pekerjaan
ditangguhkan di latar depan
Terminal sibuk" as c4
}

rectangle "**bg**
(lat belakang)" as bg_ #Lavender {
  card "Mengambil kembali pekerjaan
ditangguhkan di latar belakang
Terminal bebas" 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
Pintasan/Perintah sinyal Efek Kembali?

Ctrl+Z

SIGTSTP

Menjeda proses (beku, di memori)

Ya :`fg` ou bg

Ctrl+C

SIGINT

Matikan proses (selesai)

Tidak : proses dihancurkan

Ctrl+\

SIGQUIT

Membunuh proses + core dump

Tidak: proses dihancurkan

commande &

—

Jalankan langsung di latar belakang

`fg`untuk membawakannya kembali ke lat depan

Ctrl+Z`adalahnon destruktif. Prosesnya beku seperti yang ada, dalam memori. Anda dapat melanjutkan segera dengan`fg. Ini adalah jeda, bukan berhenti.

Siklus hidup lengkap dari sebuah pekerjaan

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

title Siklus hidup lengkap dari pekerja shell
state "tidak ada" as none
state "Foreground\n(menempati terminal)" as foreground #LightCoral
state "Dijeda\n(Ctrl+Z / SIGTSTP)" as suspended #LightYellow
state "Latar belakang\n(bg atau &)" as background #LightGreen
state "Selesai\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

Tips lanjut

fg dengan pekerjaan paling baru dan pertukaran

fg`tanpa argumen mengembalikan pekerjaan yang ditandai+(terbaru). Anda juga dapat menggunakan%-`untuk menargetkan pekerjaan sebelumnya :

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

Mengerjakan pekerjaan dengan baik

$ 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 : melepaskan dari shell

disown`Menghapus satu pekerjaan dari tabel pekerjaan shell. Proses terus berjalan tetapi tidak dapat lagi dikembalikan dengan`fg</think> (empty output)

$ ./gradlew build &
[1] 12345

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

Gabungkan dengan nohup untuk proses-proses yang lama

Agar proses dapat bertahan saat terminal ditutup:

$ 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 "Bawa pekerjaan
terbaru (+)" as f1
  card "Sasarkan pekerjaan\nspesifik: fg %n" as f2
  card "Beralih : fg %-" as f3
}

rectangle "membunuh %n" as kill_ #LightCoral {
  card "SIGTERM (bersih)" as k1
  card "SIGKILL -9 (paksa)" as k2
}

rectangle "mengalakkan" as disown #Lavender {
  card "Lepaskan dari shell
(Bertahan saat putus koneksi)" as d1
}

rectangle "nohup + &" as nohup_ #LightGreen {
  card "Proses yang diimmunisasi
terhadap SIGHUP
(masih berjalan saat penutupan
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

Jebakan dan kesalahan umum

Mengalirkan Ctrl+Z dan Ctrl+C

Ini adalah kesalahan yang paling sering.`Ctrl+C`menghentikan proses`Ctrl+Z`Dia menangguhkannya. Jika Anda menekan`Ctrl+C`Secara refleks, seluruh keadaan hilang — file terbuka, sesi LLM, build sedang berlangsung.

@startuml
skinparam backgroundColor #FEFEFE

rectangle "Ctrl+Z (SIGTSTP)" as z #LightGreen {
  card "Proses yang membeku di memori" as z1
  card "fg membawanya kembali utuh" as z2
  card "Tidak ada kerugian" as z3
}

rectangle "Ctrl+C (SIGINT)" as c #LightCoral {
  card "Proses selesai" as c1
  card "Kondisi hilang secara permanen" as c2
  card "Tidak dapat dikembalikan" as c3
}

note bottom of z
  Pause → Reprendre
end note

note bottom of c
  Kill → Perdu
end note
@enduml

Pekerjaan-pekerjaan adalah lokal untuk shell

jobs, fg et `bg`Berfungsi hanya di shell yang meluncurkan proses-proses tersebut. Jika Anda membuka terminal baru, Anda tidak akan melihat pekerjaan dari yang lain.

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

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

Untuk melihat proses system-wide, gunakan`ps` ou htop(empty)

ps aux | grep vim

Pekerjaan tidak bertahan saat shell ditutup

Jika Anda menutup terminal, semua pekerja yang ditangguhkan atau yang berjalan di latar belakang akan dihancurkan. Agar sebuah proses tetap hidup, gunakan`nohup`+disown :

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

Proses interaktif dan fg

Beberapa program interaktif tidak berjalan baik setelah satu`Ctrl+Z`+fg. Ini jarang tetapi terjadi :

  • Beberapa program yang menggunakan sinyal (vim, htop, less menangani dengan baik`Ctrl+Z`)

  • Program jaringan yang berjalan lama (ssh, opencode) biasanya pulih dengan benar

  • Program yang memodifikasi terminal (ncurses) terkadang dapat meninggalkan terminal dalam keadaan yang tidak terduga

Jika terminal rusak setelah satu`fg`, ketik :

reset

Diagram Ringkasan

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

title "fg — Tips yang mengubah semuanya"

rectangle "Masalah" as problem #LightCoral {
  card "Terminal diblokir\noleh proses" as p1
  card "Buka sebuah baru
terminal = solusi berat" as p2
}

rectangle "**Solusi**" as solution #LightGreen {
  card "Ctrl+Z → menangguhkan" as s1
  card "fg → melanjutkan" as s2
  card "bg → di latar belakang" as s3
  card "jobs → lihat yang ditangguhkan" as s4
}

rectangle "**Kelebihan**" as advantages #SkyBlue {
  card "Tidak ada kehilangan konteks" as a1
  card "Tidak ada restart" as a2
  card "Satu terminal cukup" as a3
}

problem -right-> solution : "Solusi asli\nUnix selama 40 tahun"
solution -right-> advantages : "Hasil"

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

Mengapa fg dianggap kurang?

Kebanyakan pengembang modern menemukan`fg`lambat, bahkan tidak pernah. Beberapa alasan :

  1. IDE menyembunyikan terminal: VS Code menyediakan terminal terintegrasi, tetapi tab-tab banyak membuat`fg`Terlihat kurang diperlukan

  2. Alat grafis mengganti CLI: manajer file, pemantau sistem, klien Git grafis

  3. tmux dan screen: multiplexer ini menyelesaikan masalah yang sama dengan cara yang berbeda, tapi`fg`lebih sederhana dan selalu tersedia

Namun,`fg`adalah :

  1. Universal: ada di semua shell POSIX (bash, zsh, fish…​)

  2. Tanpa ketergantungan: tidak perlu menginstal tmux atau screen

  3. seketika: dua pukulan (Ctrl+Z`lalu`fg) untuk menangguhkan dan melanjutkan

  4. Penyimpan konteks: keadaan proses masih utuh

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

rectangle "Mengapa fg adalah
diperkirakan terlalu rendah ?" as why #LightCoral {
  card "IDE dengan terminal\nmulti-tab" as w1
  card "Outils graphiques\nqui remplacent le CLI" as w2
  card "tmux/screen\nrésolvent le problème\nautrement" as w3
}

rectangle "Mengapa fg adalah
lebih baik ?" as superior #LightGreen {
  card "Universal : bash,\nzsh, fish, sh..." as s1
  card "Tanpa ketergantungan:
tidak ada instalasi" as s2
  card "Dua pukulan:
Ctrl+Z lalu fg" as s3
  card "Konteks yang terpreservasi :\nnol kehilangan status" as s4
}

why -right-> superior : "Kesederhanaan
selalu menang"
@enduml

Catatan teknis : sinyal

Untuk yang penasaran, berikut sinyal yang terlibat:

sinyal nama Dikirim oleh Efek

2

SIGINT

Ctrl+C

Interupsi — menghentikan proses

3

SIGQUIT

Ctrl+\

Keluar dengan core dump

18

SIGTSTP

Ctrl+Z

Berhenti interaktif — menghentikan proses

19

SIGCONT

fg/bg

Continue — melanjutkan proses yang ditangguhkan

15

SIGTERM

kill %n

Penghentian bersih

9

SIGKILL

kill -9 %n

Pengakhiran paksa (tidak dapat diintersep)

Alur lengkap :

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

participant "pengguna" as user
participant "cangkang" as shell
participant "Proses" 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

Kesimpulan

`fg`Bukanlah sebuah tips yang tidak jelas — ini adalah mekanisme dasar dari Unix shell, yang tersedia sejak tahun 1970-an. Fakta bahwa kebanyakan pengembang mengabaikannya adalah gejala dari jaman kita : IDE dan multiplexer telah menjauhkan kita dari dasar.

Tetapi ketika Anda berada pada server SSH, di terminal minimal, atau sekadar sedang menggunakan`opencode`dan LLM sedang bekerja penuh —Ctrl+Z, fg, bg, `jobs`adalah teman terbaik Anda.

_ Ctrl+Z menghentikan, fg melanjutkan. Ini adalah pause-play terminal. _

Artikel terkait