読了時間 : 10 minutes

あなたは始めます`./gradlew build`, ターミナルは3分間ブロックされており、待っている間に他のことをする必要がありますか?新しいタブを開く必要はありません。`Ctrl+Z`プロセスを一時停止する`fg`それはあなたが残した場所に正確に戻します。これは開発者の日常において最も過小評価されているUnixのヒントです。

目次

[]

問題:端末がビジー

すべての開発者はこの状況を経験したことがある:

$ ./gradlew build
> Building...

ターミナルがフリーズしています。もうコマンドを入力することはできません。そして、ファイルを確認して、起動する必要があります`git status`または、使用中のポートを確認する。

@startuml
skinparam backgroundColor #FEFEFE

actor Développeur as dev
participant "ターミナル" as term
participant "Gradle
( プロセス )" 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

ほとんどの開発者は新しいターミナルを開きます。しかし、もっとエレガントで速く、ネイティブなソリューションがあります:ジョブ管理です。

必須の3つのコマンド

Ctrl+Z — 一時停止 (SIGTSTP)

`Ctrl+Z`信号を送る`SIGTSTP`フォアグラウンド プロセスに。 プロセスは中断された— 死んでいない — ターミナルはプロンプトを取り戻す。

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

括弧の中の数`[1]`ですジョブ番号. Le `+`デフォルトのジョブを示します。

fg — フォアグラウンドで復帰する

`fg`サスペンドされたジョブをフォアグラウンドに戻す。プロセスは、停止した場所から正確に再開される。

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

特定のジョブ番号:

$ fg %2

bg — バックグラウンドで再開

`bg`端末をブロックせずにプロセスを再開します。長いビルドに最適です。

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

Le `&`終わりにあることは、プロセスがバックグラウンドで実行されていることを意味します。

jobs — シェルのジョブを一覧表示

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

state "前景\n(ブロックされたターミナル)" as fg #LightCoral
state "一時停止
(Ctrl+Z)" as stopped #LightYellow
state "背景
(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

シナリオ 1: 長いビルド

これは最も一般的な使用例です。Gradleのビルドを実行し、ターミナルがブロックされ、他のことをする必要があります。

@startuml
skinparam backgroundColor #FEFEFE
autonumber

actor Développeur as dev
participant "ターミナル" as term
participant "Gradle" as gradle
database "状態
プロセス" 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

ステップバイステップ

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

シナリオ2 : 忘れられた編集者

あなたは…の中にいます`vim`, 他のファイルを確認する必要があります sans 終了する`vim`.

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

しかし、それは重い。それに`Ctrl+Z`, それは即時です :

# 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 "シェル" 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

(No output?) Actually we need to output something? The instruction: "Translate from fr to ja. …​ Output only the translated text". If there is no source text, then there is nothing to translate. So output nothing. We’ll output an empty line.

</think>

(Empty)vim`その後、完全にその状態を復元します`fg: カーソル位置, バッファ内容, 元に戻す履歴 — すべて保持されます。

シナリオ3: opencodeプロセスがサスペンド

これがこの記事を書くきっかけとなったシナリオです。あなたは使っています。opencode(コード上のLLMを操作するCLIツール),そしてプロセスは一時停止されています。

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

actor Développeur as dev
participant "opcode
(LLMエージェント)" as agent
participant "シェル" 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. 再起動不要: opencode を再起動したり、コンテキストを再読み込みしたり、LLM に問題を再説明する必要はありません

シナリオ 4 : 複数のジョブを同時に管理

fg et `bg`複数のプロセスが中断されているときに、特定のプロセスを対象とするジョブ番号を受け付けます。

$ 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 "一時停止中のジョブ" as jobs #LightYellow {
  card "[1] vim config.yml" as j1
  card "[2] ./gradlew テスト" as j2
  card "[3] htop" as j3
}

rectangle "アクション" as actions #LightGreen {
  card "fg %2\n→ 前景" as a1
  card "bg %3\n→ 背景" as a2
  card "fg %1
→ 前景" 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

ジョブコマンドのサマリー

注文 �効果 例

Ctrl+Z

フォアグラウンドプロセスを一時停止

送信の`SIGTSTP`

fg

フォアグラウンドでデフォルトのジョブを再開

fg ou fg %1

fg %n

ジョブ n をフォアグラウンドで再開

fg %2

bg

バックグラウンドでデフォルトのジョブを再開します

bg ou bg %1

bg %n

ジョブ n をバックグラウンドで再開

bg %2

jobs

現在のシェルのジョブをリスト

jobs -l(PID付き)

kill %n

ジョブ n を終える

kill %2

fg、bg、Ctrl+Z、Ctrl+C、& の違い

多くの開発者はこれらのメカニズムを混同します。ここに決定的な説明があります。

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

rectangle "**Ctrl+Z**
SIGTSTP" as ctrlz #LightYellow {
  card "プロセスを一時停止します
(まだメモリに残っています)
fg/bg で利用可能" as c1
}

rectangle "**Ctrl+C**\nSIGINT" as ctrlc #LightCoral {
  card "プロセスを殺す
(戻ることはできません)
すべての状態の喪失" as c2
}

rectangle "**および **\n(背景)" as ampersand #LightGreen {
  card "直接起動して
バックグラウンドで
フリーのターミナルすぐに" as c3
}

rectangle "**fg**
(フォアグラウンド)" as fg_ #SkyBlue {
  card "ジョブを持ってきて
フォアグラウンドで一時停止
ターミナルが使用中" as c4
}

rectangle "**bg**\n(背景)" as bg_ #Lavender {
  card "ジョブを再開しろ
バックグラウンドで一時停止中
空きターミナル" 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
ショートカット/コマンド 信号 効果 �戻る?

Ctrl+Z

SIGTSTP

プロセスを一時停止する(凍結、メモリ上)

はい :`fg` ou bg

Ctrl+C

SIGINT

プロセスを終了させる (完了)

いいえ : プロセスが破壊されました

Ctrl+\

SIGQUIT

プロセスを kill + コアダンプ

いいえ: 破壊されたプロセス

commande &

—

バックグラウンドで直接起動

`fg`それを前面に出すために

`Ctrl+Z`です非破壊的. プロセスはそのまま固定され、メモリに保持されています。あなたはすぐに再開できますに`fg`これは pause であって、 stop ではありません。

ジョブの完全なライフサイクル

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

title シェルジョブの完全なライフサイクル
state "存在しない" as none
state "前景\n(ターミナルを占有します)" as foreground #LightCoral
state "一時停止\n(Ctrl+Z / SIGTSTP)" as suspended #LightYellow
state "背景
(bg または &)" as background #LightGreen
state "完了\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

高度なヒント

fg 最新の仕事と交互に

fg`引数なしでは、マークされたジョブが戻ります+(最新の)。 しかし、あなたはまた使用することもできます%-`前のジョブを対象にする :

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

désown : シェルから切り離す

disown`シェルのジョブテーブルからジョブを削除します。プロセスは実行を継続しますが、再度呼び出すことはできません。`fg:

$ ./gradlew build &
[1] 12345

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

長いプロセスに対して nohup と組み合わせる

ターミナルが閉じられたときにプロセスが生き残るように:

$ 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 "最新のジョブを戻す\n(+)" as f1
  card "仕事を狙う
特定 : fg %n" as f2
  card "交互 : fg %-%" as f3
}

rectangle "殺す %n" as kill_ #LightCoral {
  card "SIGTERM (クリーン)" as k1
  card "SIGKILL -9 (強制)" as k2
}

rectangle "縁を切る" as disown #Lavender {
  card "シェルから切り離す
(ログアウト後も生存する)" as d1
}

rectangle "nohup + &" as nohup_ #LightGreen {
  card "免疫プロセス
SIGHUPに対して
(端末の終了に耐える
端末の)" 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を混同する

これが最も頻繁な間違いです。`Ctrl+C`プロセスを殺す。`Ctrl+Z`それを一時停止します。もしあなたが押すと`Ctrl+C`反射的に、すべての状態が失われます — 開いているファイル、LLMセッション、進行中のビルド。

@startuml
skinparam backgroundColor #FEFEFE

rectangle "Ctrl+Z (SIGTSTP)" as z #LightGreen {
  card "メモリ上で凍結しているプロセス" as z1
  card "fg はそれを無傷のまま連れ戻す" as z2
  card "損失なし" as z3
}

rectangle "Ctrl+C (SIGINT)" as c #LightCoral {
  card "プロセス終了" as c1
  card "状態は永久に失われた" as c2
  card "返品はできません" as c3
}

note bottom of z
  Pause → Reprendre
end note

note bottom of c
  Kill → Perdu
end note
@enduml

ジョブはシェルにローカルです

jobs, fg et `bg`ジョブは、それらを起動したシェル内でのみ機能します。新しいターミナルを開くと、他のジョブは表示されません。

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

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

システム全体のプロセスを見るには、ps ou htop:

ps aux | grep vim

ジョブはシェルの終了後に生き残らない

ターミナルを閉じると、一時停止またはバックグラウンドで実行中のすべてのジョブが破棄されます。プロセスが存続するようにするには、使ってください`nohup`+disown(Empty)

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

対話型プロセスと fg

一部のインタラクティブなプログラムはその後良くない状態になる`Ctrl+Z` + fg. 稀ですが、起こります:

  • シグナルを使用する一部のプログラムは(vim、htop、lessはうまく機能しています`Ctrl+Z`)

  • 長時間のネットワークプログラム (ssh、opencode) は通常、正常に取得できます

  • ターミナル (ncurses) を変更するプログラムは、ときどきターミナルを予期しない状態に残すことがあります

端末が破損した後の`fg`, 入力して :

reset

サマリーダイアグラム

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

title "fg — すべてを変えるチップ"

rectangle "問題" as problem #LightCoral {
  card "端末がブロックされました
プロセスによって" as p1
  card "開ける 一つの 新しい\nターミナル = 解決策 重い" as p2
}

rectangle "**解答**" as solution #LightGreen {
  card "Ctrl+Z → 一時停止" as s1
  card "fg → 再開する" as s2
  card "bg → 背景" as s3
  card "jobs → サスペンドされたものを表示" as s4
}

rectangle "利点" as advantages #SkyBlue {
  card "コンテキストの損失なし" as a1
  card "再起動なし" as a2
  card "ターミナル1つで十分です" as a3
}

problem -right-> solution : "Unixネイティブソリューション\n40年間"
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

なぜ fg が過小評価されているのか

ほとんどの最新の開発者は発見する`fg`�遅れたり、あるいは決して起こらないこともあります。 いくつかの理由:

  1. IDEはターミナルを隠す: VS Codeは統合ターミナルを提供しますが、複数のタブは`fg`表面的には必要性が低い

  2. グラフィカルツールは CLI を置き換えるファイルマネージャー、システムモニター、グラフィカルGitクライアント

  3. tmux と screen: これらのマルチプレクサは同じ問題を異なる方法で解決しますが`fg`よりシンプルで常に利用可能です

しかし、`fg`は:

  1. 普遍的: POSIXシェルすべてに存在する (bash, zsh, fish…​)

  2. 依存性のない: tmuxまたはscreenをインストールする必要はありません

  3. スナップショット: 2回の打撃 (Ctrl+Z`それから`fg) 一時停止および再開する

  4. コンテキスト保存者: プロセスの状態は無傷です

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

rectangle "なぜ fg は
過小評価されているのでしょうか?" as why #LightCoral {
  card "ターミナル付きIDE
マルチタブ" as w1
  card "グラフィカルツール
CLIを置き換える" as w2
  card "tmux/screen
問題を解決します
あるいは" as w3
}

rectangle "なぜ fg は
優れているのでしょうか?" as superior #LightGreen {
  card "汎用的 : bash,\nzsh, fish, sh..." as s1
  card "依存なし:\nインストール不要" as s2
  card "2つのキー操作:\nCtrl+Z と fg" as s3
  card "保持されたコンテキスト:
状態損失ゼロ" as s4
}

why -right-> superior : "シンプルさ
いつも勝つ"
@enduml

技術的なメモリ: 信号

興味のある方へ、関与している信号は以下の通り:

信号 名前 送信者 �効果

2

SIGINT

Ctrl+C

中断 — プロセスを終了します

3

SIGQUIT

Ctrl+\

コアダンプを伴って終了

18

SIGTSTP

Ctrl+Z

対話的な停止 — プロセスを一時停止

19

SIGCONT

fg/bg

続ける — 一時停止されたプロセスを再開する

15

SIGTERM

kill %n

正常な終了

9

SIGKILL

kill -9 %n

強制終了 (インターセプト不可能)

完全なフロー :

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

participant "ユーザー" as user
participant "シェル" as shell
participant "プロセス" 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

結論

`fg`これは obscure tips ではない — Unix シェルの基本的なメカニズムで、1970 年代から利用可能です。ほとんどの開発者がこれを無視するのは、私たちの時代の症状です:IDE とマルチプレクサーが私たちを基本から遠ざけている。

しかし、SSHサーバーにいるとき、ミニマルなターミナルで、あるいは単純に使っているときでも`opencode`そしてLLMはまさに作業中です —Ctrl+Z, fg, bg, `jobs`彼らはあなたの親友です。

_ Ctrl+Zで一時停止、fgで再開。これはターミナルの一時停止・再生です。 _

関連記事