وقت القراءة: 10 minutes

أنت تطلق`./gradlew build`, يتم حظر المحطة لمدة 3 دقائق، وتحتاج إلى القيام بشيء آخر أثناء الانتظار؟ لا حاجة لفتح علامة تبويب جديدة.`Ctrl+Z`يوقف العملية,`fg`يعيده بالضبط إلى المكان الذي تركته فيه. إنه النصيحة Unix الأكثر تقليلاً من التقدير في روتين المطور اليومي.

طُق

[]

المشكلة: طرفية مشغولة

كل مطور قد واجه هذه الحالة :

$ ./gradlew build
> Building...

الطرفية متوقفة. لم يعد بإمكانك كتابة أي أمر. وأنت بحاجة إلى استعراض ملف، تشغيل (Note: There is a trailing space after "تشغيل" as in the original fragment.)git status, أو التحقق من منفذ مشغول.

Failed to generate image: PlantUML preprocessing failed: [From <input> (line 6) ]

@startuml
skinparam backgroundColor #FEFEFE

actor Développeur as dev
participant "النهاية" as term
participant "Gradle
^^^^^
 Syntax Error? (Assumed diagram type: sequence)

@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

معظم المطورين يفتحون وحدة طرفية جديدة. ولكن هناك حلًا أكثر أناقة، وأسرع، وناتي: إدارة المهام.

الثلاثة الأوامر الضرورية

Ctrl+Z — إيقاف (SIGTSTP)

`Ctrl+Z`يُرسل الإشارة`SIGTSTP`إلى العملية في المقدمة. العملية هيمعلق— غير مقتول — و استعاد terminal موجهه.

$ ./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`يستأنف العملية بدون حظرterminal. مثالي للبناءات الطويلة.

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

Le `&`في النهاية يعني أن العملية تعمل في الخلفية.

jobs — قائمة وظائف الغلاف

$ jobs
[1]-  Stoppé    vim README.md
[2]+  En cours   ./gradlew build
Failed to generate image: PlantUML preprocessing failed: [From <input> (line 5) ]

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

state "الواجهة الأمامية
^^^^^
 Syntax Error? (Assumed diagram type: sequence)

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

state "الواجهة الأمامية
(الطرفية محظورة)" as fg #LightCoral
state "معلق\n(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، والطرفيّة متوقفة، وتحتاج إلى فعل شيء آخر.

Failed to generate image: PlantUML preprocessing failed: [From <input> (line 8) ]

@startuml
skinparam backgroundColor #FEFEFE
autonumber

actor Développeur as dev
participant "طرفية" as term
participant "Gradle" as gradle
database "الحالة
^^^^^
 Syntax Error? (Assumed diagram type: sequence)

@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`, تحتاج إلى مراجعة ملف آخر دون الخروج`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
vim suspend

( empty )`vim`يستعيد حالته تمامًا بعد`fg`موقع المؤشر، محتوى المخزن المؤقت، سجل التراجع — كل شيء محفوظ.

السيناريو 3: عملية opencode معلقة

هذا هو السيناريو الذي حفز هذا المقال. أنت تستخدم`opencode`(أداة سطر أوامر لتشغيل نموذج لغوي كبير على كودك)، وال عملية معلقة.

Failed to generate image: PlantUML preprocessing failed: [From <input> (line 7) ]

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

actor Développeur as dev
participant "opencode
^^^^^
 Syntax Error? (Assumed diagram type: sequence)

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

actor Développeur as dev
participant "opencode
(وكيل نموذج لغوي كبير)" as agent
participant "قشرة" as shell
participant "جيت" 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
multiple jobs

ملخص أوامر الوظائف

طلب تأثير مثال

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 و &

كثير من المطورين يخلطون بين هذه الآليات. هنا توضيح حاسم.

Failed to generate image: PlantUML preprocessing failed: [From <input> (line 6) ]

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

rectangle "**Ctrl+Z**
SIGTSTP" as ctrlz #LightYellow {
^^^^^
 Syntax Error? (Assumed diagram type: activity)

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

rectangle "**Ctrl+Z**
SIGTSTP" as ctrlz #LightYellow {
  card "علق العملية
(is لا يزال في الذاكرة)
يمكن استخدامه مع 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 "**الخلفية**
(الخلفية)" as bg_ #Lavender {
  card "استأنف مهمة معلقة في الخلفية\nطرفية حرة" 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

قتل العملية + تفريغ الذاكرة

لا : عملية مدمرة

commande &

—

شغل في الخلفية مباشرة

`fg`لإعادته إلى المقدمة

Ctrl+Z`هوغير اتلافي. العملية متجمدة كما هي، في الذاكرة. يمكنك المتابعة فورًا مع`fg. هذه pause، ليس stop

الدورة الكاملة لحياة الوظيفة

Failed to generate image: PlantUML preprocessing failed: [From <input> (line 8) ]

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

title دورة حياة كاملة لوظيفة شل
state "غير موجود" as none
state "الواجهة الأمامية\n(يشغل الطرفي)" as foreground #LightCoral
state "معلق
^^^^^
 Syntax Error? (Assumed diagram type: state)

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

title دورة حياة كاملة لوظيفة شل
state "غير موجود" as none
state "الواجهة الأمامية\n(يشغل الطرفي)" as foreground #LightCoral
state "معلق
(Ctrl+Z / SIGTSTP)" as suspended #LightYellow
state "الخلفية
(bg أو &)" as background #LightGreen
state "مكتمل\n(كود الخروج 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`بدون حجة يعيد تشغيل المهمة المحددة+(الأحدث). لكنك يمكنك أيضًا استخدام%-`لاستهداف الوظيفة السابقة :

$ 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
Failed to generate image: PlantUML preprocessing failed: [From <input> (line 7) ]

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

rectangle "fg" as fg_ #SkyBlue {
  card "أَحضر الوظيفة
الأحدث (+)" as f1
^^^^^
 Syntax Error? (Assumed diagram type: activity)

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

rectangle "fg" as fg_ #SkyBlue {
  card "أَحضر الوظيفة
الأحدث (+)" 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
(يستمر رغم الإغلاق
من 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

المصائد والأخطاء الشائعة

الخلط بين Ctrl+Z و Ctrl+C

هذا هو الخطأ الأكثر شيوعًا.`Ctrl+C`يقتل العملية.`Ctrl+Z`يوقفه. إذا ضغطت على`Ctrl+C`كرد فعل، كل الحالة ضاعت — ملفات مفتوحة، جلسات LLM، البناءات جارية.

ctrlz vs ctrlc

الوظائف محلية إلى الغلاف

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:

$ 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

مخطط ملخص

Failed to generate image: PlantUML preprocessing failed: [From <input> (line 27) ]

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

title "fg — النصيحة التي تغير كل شيء"

rectangle "**مشكلة**" as problem #LightCoral {
  card "محطة مغلقة\nبعملية" as p1
  card "فتح محطّة جديدة\nالمحطة = حلّ ثقيل" as p2
}

rectangle "**الحل**" as solution #LightGreen {
  card "Ctrl+Z → تعليق" as s1
  card "fg → يستأنف" as s2
  card "bg → في الخلفية" as s3
  card "الوظائف → عرض المعلقين" as s4
}

rectangle "**المزايا**" as advantages #SkyBlue {
  card "لا فقدان للسياق" as a1
  card "لا إعادة تشغيل" as a2
  card "يكفي محطة واحدة" as a3
}

problem -right-> solution : "الحل الأصلي
Unix منذ 40 سنة"
^^^^^
 Syntax Error? (Assumed diagram type: component)

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

title "fg — النصيحة التي تغير كل شيء"

rectangle "**مشكلة**" as problem #LightCoral {
  card "محطة مغلقة\nبعملية" as p1
  card "فتح محطّة جديدة\nالمحطة = حلّ ثقيل" as p2
}

rectangle "**الحل**" as solution #LightGreen {
  card "Ctrl+Z → تعليق" as s1
  card "fg → يستأنف" as s2
  card "bg → في الخلفية" as s3
  card "الوظائف → عرض المعلقين" as s4
}

rectangle "**المزايا**" as advantages #SkyBlue {
  card "لا فقدان للسياق" as a1
  card "لا إعادة تشغيل" as a2
  card "يكفي محطة واحدة" 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

لماذا fg غير مُقدر؟

معظم المطورين الحديثين يكتشفون`fg`متأخرًا، أو حتى أبدًا. بعض الأسباب:

  1. تخفي بيئات التطوير المتكاملة الطرفية: VS Code يقدم محطة طرفية مدمجة، لكن علامات التبويب المتعددة تجعل`fg`أقل ضرورة ظاهري

  2. الأدوات الرسومية تحل محل واجهات سطر الأوامر: مديري الملفات, مراقبو النظام, عملاء Git الرسوميون

  3. tmux و screen: هذه المتعدِّدات تحل نفس المشكلة بطريقة مختلفة، لكن`fg`هو أكثر بساطة ومتوفر دائمًا

ومع ذلك،fg:

  1. عالمي: موجود في جميع أصداف POSIX (bash, zsh, fish…​)

  2. بدون اعتمادلا تحتاج إلى تثبيت tmux أو screen

  3. لحظي: ضربتان (Ctrl+Z ثم`fg`) لإيقاف وإعادة التشغيل

  4. حافظ السياقحالة العملية سليمة

Failed to generate image: PlantUML preprocessing failed: [From <input> (line 6) ]

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

rectangle "لماذا fg هو
قليل التقدير ?" as why #LightCoral {
^^^^^
 Syntax Error? (Assumed diagram type: activity)

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

rectangle "لماذا fg هو
قليل التقدير ?" as why #LightCoral {
  card "بيئة تطوير متكاملة مع الطرفية
علامات تبويب متعددة" as w1
  card "أدوات رسومية
التي تستبدل واجهة سطر الأوامر" as w2
  card "tmux/screen\nحلّ المشكلة\nبشكل آخر" as w3
}

rectangle "لماذا fg هو
أعلى؟" as superior #LightGreen {
  card "عام : bash,\nzsh, fish, sh..." as s1
  card "بدون تبعية:
لا تثبيت" as s2
  card "ضربتان:\nCtrl+Z ثم fg" as s3
  card "السياق محفوظ :\nصفر فقدان الحالة" 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

إنهاء قسري (غير قابل للاعتراض)

التدفق الكامل:

signal flow

خاتمة

`fg`ليس نصيحة غامضة — بل هو آلية أساسية في شل يونكس، متوفر منذ السبعينيات. أن يتجاهل معظم المطورين هذا الأمر هو أحد أعراض عصرنا: بيئات التطوير المتكاملة ومعدّلات المستخدمين أبعدتنا عن الأساسيات.

لكن عندما تكون على خادم SSH، في طرفية بسيطة، أو ببساطة أثناء الاستخدام`opencode`وأن نموذج اللغة الكبير في حالة عمل كامل —Ctrl+Z, fg, bg, `jobs`هم أصدقاؤكم الأفضلاء.

_ Ctrl+Z يوقف، fg يستأنف. هذا هو زر الإيقاف المؤقت-التشغيل للمحطة. _

Articles connexes