(ب) أن بناء قذيفة من الخدش في (جيم) يظل أحد أفضل الطرق لتعميق فهمك لكيفية إدارة نظم التشغيل للعمليات، ومعالجة مدخلات المستخدمين، وتنفيذ البرامج، وفي حين أن القذائف الحديثة مثل (باش) و(زش) و(فيش) متطورة بشكل لا يصدق، فإن وظائفها الأساسية تغلي إلى حلقة بسيطة: قراءة القيادة، وقطعها، وخلق عملية جديدة، وانتظر الانتهاء من هذا الدليل الموسع.

ما الذي تفعله (شيل) في الواقع

At its heart, a shell is a command-line interpreter, it provides a textual interface where users type commands, and the shell translates those commands into actions performed by the operating system. When you type ls -la, the shell seem must find the ls executable

بناء قذيفة صغيرة يعلمك عنها

  • قراءة المدخلات القياسية وتجميعها
  • Creating and managing child processes with fork
  • اعادة صياغة صورة الذاكرة العملية مع
  • ترجمة:
  • معالجة الأخطاء المشتركة ببراعة

فهم هذه المباني يعطيك نظرة عن كيفية عمل جميع النظم شبه الموحدة تحت غطاء الرأس، ويوفر أساسا صلبا للتعلم عن سمات أكثر تقدما مثل مناولة الإشارات، ومراقبة الوظائف، والاتصال بين العمليات.

وضع صمامات الشل

كل قذيفة مبنية حول حلقة رئيسية تتردد إلى ما لا نهاية حتى يطلب المستخدم الخروج من هذه الحلقة تطبع بسرعة وتقرأ خطا من المدخلات ثم تدقها ثم تتصرف على القيادة المقطعية

while (1) {
 print_prompt();
 read_input();
 parse_input();
 execute_command();
}

وفي جيم، تستخدم عادة ] فواكه لقراءة مدخلات لأنها تتعامل مع حدود خطية وتدفقات احتياطية أكثر أمانا من ] غايات ، ويمكن أن يكون العجلة بسيطة مثل

معالجة قضايا العصر في المدخلات

ونادرا ما تكون مدخلات المستخدمين نظيفة، إذ يجب أن تُعالج القصف القوي الخطوط الفارغة، والقيادة والمسار الأبيض، والقيادات الطويلة للغاية، وحالة نهاية العجلات (Ctrl+D). وإذا كان النبات ، فإن أي شيء ينبغي أن يُعادل ، إذا كان ينبغي أن يُثبت بشكل غير مباشر.

#define MAX_INPUT 1024

char input[MAX_INPUT];
if (fgets(input, MAX_INPUT, stdin) == NULL) {
 printf("\n");
 break; // EOF
}

// Remove trailing newline, if present
size_t len = strlen(input);
if (len > 0 && input[len-1] == '\n') {
 input[len-1] = '\0';
} else {
 // Input too long, flush remaining characters
 int ch;
 while ((ch = getchar()) != '\n' && ch != EOF);
}

أوامر الفرز في الحج

بمجرد أن يكون لديكِ خيط مدخل نظيف، يجب أن تقسميه إلى كسور، أول من يُدعى القائد (مثلاً، )

char *args[MAX_ARGS];
int arg_count = 0;

args[arg_count] = strtok(input, " \t");
while (args[arg_count] != NULL && arg_count < MAX_ARGS - 1) {
 arg_count++;
 args[arg_count] = strtok(NULL, " \t");
}
args[arg_count] = NULL; // execvp expects a NULL-terminated array

هذا المركب يقسم المدخلات على الأماكن والرسومات، بل يتعامل مع الخيوط المقتبسة، لذا فإن الأمر مثل ]echo:hello world]] سوف يخترق بشكل غير صحيح ثلاثة أكاذيب بدلا من اثنين.

بعد التكسير، يجب أن تتحققوا إذا كان أول من يُدعى (قوة القيادة الفارغة) وإذا كان الأمر كذلك، فإنهم سيستمرون في التكرار التالي للحلقة دون أن يُسرحوا.

بناء القيادة

لا يجب أن تُظهر جميع الأوامر عملية جديدة، بعض الأوامر، مثل cd و]

Exit

The exit command terminated the shell immediately. It is the simplest built-in to implement: just check if the first token equals `exit" and break out of the main cycle. Optionally, you can accept an exit status argument and pass it to the exit system call.

دليل التغيير (ج)

cd command requires you to call ]chdir . The target directory is the second argue. If no argue is provided, you might default to the user's home directory (available via the [FLT check:4]HOME[F value environment]

if (strcmp(args[0], "cd") == 0) {
 const char *path = args[1];
 if (path == NULL) {
 path = getenv("HOME");
 if (path == NULL) {
 fprintf(stderr, "cd: HOME not set\n");
 continue;
 }
 }
 if (chdir(path) != 0) {
 perror("cd");
 }
 continue; // skip fork/exec
}

عملية إنشاء الشوكة

أي قيادة ليست مبنية يجب أن تخلق قذيفة عملية طفل لتنفيذها نظام fork ينشئ عملية جديدة بتكرار عملية الاتصال العملية الجديدة تسمى الطفل، والوالد الأصلي هو بعد

pid_t pid = fork();
if (pid == -1) {
 perror("fork");
 continue;
}

if (pid == 0) {
 // Child process
 // ...
} else {
 // Parent process
 // ...
}

لماذا شوك؟

قد تتساءلون لماذا تحتاجون إلى إنشاء عملية منفصلة على الإطلاق، والسبب هو أن exec، الذي يحمّل برنامجاً جديداً إلى الذاكرة، يحل محل العملية الحالية تماماً، وإذا كانت القصف يُدعى ]exec] مباشرة، فإن برنامج القصف سيُستعاض عنه ولن يعود أبداً لقبول الأوامر الجديدة،

تنفيذ برنامج مع

exec family of functions replaces the current process with a new program. There are several variants: ]execl, execlp

if (pid == 0) {
 // Child process
 execvp(args[0], args);

 // If execvp returns, an error occurred
 perror("exec");
 exit(EXIT_FAILURE);
}

ملاحظة النداء إلى ] بعد ]perror. وإذا ] ]] فشل (مثلا، لأن القيادة لا وجود لها)، فإن عملية الطفل يجب أن تنتهي، خلافا لذلك، أنها ستواصل تشغيل أي رمز يتبعه.

انتظار عملية الطفل

وبعد الاستغناء عن عملية الوالدين، تنتظر عادة الطفل أن ينتهي قبل أن يدفع مرة أخرى، ويتم ذلك بـ wait أو ] التي تنتظر .

int status;
waitpid(pid, &status, 0);

(أ) [(FLT:0]status)تغيير يتضمن معلومات عن كيفية إنهاء الطفل، ويمكنك استخدام الكليات مثل ]WIFEXITED، ]

Blocking vs. Non-Blocking

(أ) أن يُطلب من الأب قبل أن يخرج الطفل، وهذا هو السلوك الصحيح لعملية مُراعية، وإذا ما أضيفت لاحقاً الدعم لعمليات المعلومات الأساسية (تُدير قيادة مع ) تحتاج إلى قائمة، و[()، ستُديرون [الخيار 5]

وضع معاً الصدمة الكاملة

وهنا قذيفة كاملة ودنيا تدمج جميع القطع التي نوقشت حتى الآن، وهي تتناول exit] و](ج) ) البني - الزينات، والبرقيات المستخدمة [() [للإختبار:5]، وللتحقق من وضوحات الخارجية، وانتظر.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>

#define MAX_INPUT 1024
#define MAX_ARGS 64

int main(void) {
 char input[MAX_INPUT];
 char *args[MAX_ARGS];
 int should_run = 1;

 while (should_run) {
 printf("mysh> ");
 fflush(stdout);

 if (fgets(input, MAX_INPUT, stdin) == NULL) {
 printf("\n");
 break;
 }

 // Remove trailing newline
 size_t len = strlen(input);
 if (len > 0 && input[len-1] == '\n') {
 input[len-1] = '\0';
 }

 // Tokenize
 int i = 0;
 args[i] = strtok(input, " \t");
 while (args[i] != NULL && i < MAX_ARGS - 1) {
 i++;
 args[i] = strtok(NULL, " \t");
 }
 args[i] = NULL;

 if (args[0] == NULL) {
 continue; // empty line
 }

 // Handle built-in commands
 if (strcmp(args[0], "exit") == 0) {
 should_run = 0;
 continue;
 }
 if (strcmp(args[0], "cd") == 0) {
 const char *path = args[1];
 if (path == NULL) {
 path = getenv("HOME");
 }
 if (chdir(path) != 0) {
 perror("cd");
 }
 continue;
 }

 // Fork and execute external command
 pid_t pid = fork();
 if (pid < 0) {
 perror("fork");
 continue;
 }

 if (pid == 0) {
 // Child
 execvp(args[0], args);
 perror("exec");
 exit(EXIT_FAILURE);
 } else {
 // Parent waits
 int status;
 waitpid(pid, &status, 0);
 }
 }

 return 0;
}

[FLT] Myshell. [FLT:]

الشلالات المشتركة وسلاسل الديون

حتى مع هذا القدر الصغير من الرموز، هناك العديد من الأمور يمكن أن تسوء هنا أكثر القضايا شيوعاً وكيفية إصلاحها:

القيادة لم تجد

إذا قمت بكتابة أمر غير موجود (مثلاً، foobar])،

مفقودين من طراز Newline أو من طراز RUncated

وإذا ظهر سرعتك دون انتظار مدخلات، فإن السبب المحتمل هو أن تكون الشخصية المتبقية في مدخل احتياطي من نداء سابق، وتحقق دائما من أن فوجئ ] قد استهلكت الخط بأكمله (أي أن آخر طابع قبل أن يصبح المبيد الباطل خطا جديدا).

عمليات الزومبي

إذا نسيت أن تتصل في انتظار [أو ] في انتظار ، فإن عمليات الأطفال التي تنتهي تصبح زومبياً إلى أن تستعيدها، ولكن القصف في النموذج يدعو إلى التراكم ، ولكن ينبغي أن تظهر لاحقاً

توسيع نطاق الشيل

بمجرد أن تعملي القصف الأساسي يمكنكِ إضافة سمات تقرب من قذيفة العالم الحقيقي كل سمة تعلمكِ المزيد عن نظام التشغيل

توجيه المدخلات/النواتج

Supporting [FLT:] ], [FLT:[lt;, and inputgt; requires you to parse the command line for these operators, open the appropriate files using

القراصنة

(ب) إن وضع ناتج قيادة واحدة في مدخلات أخرى ()cmd1 ⁇ cmd2 ) هو أكثر مشاركة، تحتاج إلى إنشاء أنبوب مع ]pipe ، وشوك عمليتين من عمليات الطفل، وإعادة توجيه ناتج طفل واحد إلى نهاية الأنبوب والنهاية الأخرى، على أن يكتمل المدخلات.

مراقبة الوظائف

Adding background execution ( managemed;] at the end of a command) and the ability to bring jobs to the foreground requires managing a job table, handling ]SIGTSTP, SIGCONT

تاريخ القيادة

Implementation a simple history mechanism (up/down arrows to recall previous commands) involves capturing input using raw terminal mode (via tcgetattr and ]tcsetattr) or using the readline[FLT functioning:5]

المزيد من القراءة والموارد

ولتعميق فهمكم للمفاهيم المعروضة هنا، فإن الموارد التالية لا تقدر بثمن:

خاتمة

بناء قذيفة أساسية في (سي) هو أكثر من تدريب أكاديمي، يرغمك على المشاركة مباشرة في خلاصات نظام التشغيل الأساسي، لقد رأيت كيف تقرأ وتقطع مدخلات المستخدمين، كيف أن ]