国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

北京 順義 網(wǎng)站制作培訓(xùn)網(wǎng)站制作

北京 順義 網(wǎng)站制作,培訓(xùn)網(wǎng)站制作,wordpress主頁 無法連接數(shù)據(jù)庫,臺州網(wǎng)站建設(shè) 網(wǎng)站制作 網(wǎng)站設(shè)計個人主頁:chian-ocean 文章專欄-Linux 前言: Shell(外殼)是一個操作系統(tǒng)的用戶界面,它提供了一種方式,使得用戶能夠與操作系統(tǒng)進行交互。Shell 是用戶與操作系統(tǒng)之間的橋梁,允許用戶通過命令行…

個人主頁:chian-ocean

文章專欄-Linux

前言:

Shell(外殼)是一個操作系統(tǒng)的用戶界面,它提供了一種方式,使得用戶能夠與操作系統(tǒng)進行交互。Shell 是用戶與操作系統(tǒng)之間的橋梁,允許用戶通過命令行輸入來執(zhí)行各種操作,例如文件管理、程序執(zhí)行、進程控制、系統(tǒng)監(jiān)控等

在這里插入圖片描述

常見的 Shell 類型:

  1. Bash(Bourne Again Shell)
    • 是 Linux 和 macOS 等類 Unix 系統(tǒng)中常見的默認 Shell。它是 Bourne Shell 的增強版,支持豐富的特性,如命令補全、歷史命令、數(shù)組等。
  2. Zsh(Z Shell)
    • 是一個功能強大的 Shell,支持更豐富的自動化、命令補全、插件系統(tǒng)等特性。Zsh 常常被認為是最為用戶友好的 Shell 之一。
  3. Fish(Friendly Interactive Shell
    • 是一個具有用戶友好界面和豐富特性(如自動提示、自動補全等)的現(xiàn)代 Shell。其設(shè)計注重簡潔和易用性。
  4. C Shell(csh)
    • 基于 C 語言語法的 Shell,主要用于早期的 Unix 系統(tǒng)。C Shell 提供了較強的腳本編程功能。
  5. Korn Shell(ksh)
    • 是一個功能強大的 Shell,結(jié)合了 Bourne Shell 和 C Shell 的特性,并且提供了很多增強的功能。

shell外殼的實現(xiàn)

引入頭文件

#include<string>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<assert.h>
  • #include<string>:引入 C++ 的 string 庫,用于字符串處理。

  • #include<unistd.h>:提供訪問系統(tǒng)調(diào)用的接口,例如 fork()、execvp()、getcwd() 等。

  • #include<sys/wait.h>:包含等待子進程退出的函數(shù)。

  • #include<sys/types.h>:包含系統(tǒng)數(shù)據(jù)類型的定義,如 pid_t(進程 ID 類型)。

  • #include<stdlib.h>:提供一些標(biāo)準(zhǔn)庫函數(shù),如 exit()、getenv()putenv() 等。

  • #include<stdio.h>:提供輸入輸出函數(shù),如 printf()

  • #include<string.h>:提供字符串操作函數(shù),如 strtok()、strcmp() 等。

  • #include<assert.h>:提供調(diào)試宏 assert(),用于檢測程序中的錯誤

宏定義

#define DELIM " \t"
#define LEFT "["
#define RIGHT "]"
#define LABLE "$"
#define LINE_SIZE 1024
#define ARGC_SIZE 32
#define EXIT_CODE 4
  • DELIM:命令行參數(shù)的分隔符,包含空格和制表符。

  • LEFT, RIGHT, LABLE:格式化命令行提示符的符號,用于顯示用戶、主機和當(dāng)前工作目錄。

  • LINE_SIZE:最大命令行字符長度,設(shè)置為1024。

  • ARGC_SIZE:最大命令行參數(shù)數(shù)量,設(shè)置為32。

  • EXIT_CODE:用于退出的錯誤代碼。

全局變量

int quit = 0;
int LASTCODE = 0;
char* argv[ARGC_SIZE];
char commondline[LINE_SIZE];
char pwd[ARGC_SIZE];
char myenv[ARGC_SIZE];
  • quit:控制程序是否退出的標(biāo)志。

  • LASTCODE:記錄上一個命令的退出狀態(tài)碼。

  • argv:存儲命令行解析后的參數(shù)。

  • commondline:存儲輸入的命令行字符串。

  • pwd:存儲當(dāng)前工作目錄路徑。

  • myenv:存儲環(huán)境變量。

const char* getusr()
{return getenv("USER");
}const char* gethostname()
{return getenv("HOSTNAME");
}
  • getusr:返回當(dāng)前用戶的用戶名。
  • gethostname:返回當(dāng)前計算機的主機名。

獲取當(dāng)前工作目錄

void getpwd()
{getcwd(pwd, sizeof(pwd));
}
  • getpwd:調(diào)用 getcwd 獲取當(dāng)前工作目錄,并將結(jié)果存儲在 pwd 中。

交互式輸入處理

void ineract(char* cline, int size)
{getpwd();printf(LEFT"%s@%s %s"RIGHT""LABLE" ", getusr(), gethostname(), pwd);char* s = fgets(cline, size, stdin);assert(s);(void)s;cline[strlen(cline) - 1] = '\0';
}

ineract 函數(shù)是命令行交互的核心部分,用于顯示提示符并獲取用戶輸入。以下是對代碼逐行的解析:

函數(shù)定義

void ineract(char* cline, int size)
  • cline:指向存儲用戶輸入命令的字符數(shù)組的指針。
  • size:輸入緩沖區(qū)的大小,表示 cline 數(shù)組的最大容量。

獲取當(dāng)前工作目錄并顯示提示符

getpwd();
printf(LEFT"%s@%s %s"RIGHT""LABLE" ", getusr(), gethostname(), pwd);
  • getpwd():調(diào)用 getpwd 函數(shù)來獲取當(dāng)前工作目錄并存儲到全局變量 pwd 中。

  • printf:顯示命令行提示符。格式為 [user@hostname pwd]$,其中:

    • getusr():獲取當(dāng)前用戶名(通過環(huán)境變量 USER)。
    • gethostname():獲取當(dāng)前主機名(通過環(huán)境變量 HOSTNAME)。
    • pwd:顯示當(dāng)前工作目錄。

    提示符通過格式化字符串顯示,LEFTRIGHT 用于添加方括號([])包圍信息,而 LABLE 是一個 $ 字符,表示命令行提示符。

獲取用戶輸入

char* s = fgets(cline, size, stdin);
assert(s);
(void)s;
  • fgets(cline, size, stdin):從標(biāo)準(zhǔn)輸入(鍵盤)讀取用戶輸入,存儲在 cline 數(shù)組中,最多讀取 size-1 個字符。fgets 會自動在輸入末尾添加一個 \0 來終止字符串。
  • assert(s):如果 fgets 返回 NULL,程序?qū)⒔K止并輸出錯誤信息。assert 是一種調(diào)試檢查,確保輸入讀取成功。如果 sNULL,說明讀取輸入失敗。
  • (void)s(void)s 的作用是消除未使用變量 s 的編譯器警告,實際上這里并沒有做任何事情。

去除輸入末尾的換行符

cline[strlen(cline) - 1] = '\0';
  • strlen(cline) - 1:計算輸入字符串的長度,并將其最后一個字符(換行符 \n)替換為字符串結(jié)束符 \0。這一步去除 fgets 讀取時可能留下的換行符。

命令行解析

int AnalyzeCommandLine(char* cline)
{int i = 0;argv[i++] = strtok(cline, DELIM);while (argv[i++] = strtok(NULL, DELIM));return i - 1;
}

AnalyzeCommandLine 函數(shù)用于解析輸入的命令行字符串,并將解析出的各個命令參數(shù)存儲在 argv 數(shù)組中。以下是對該函數(shù)的逐行解析:

函數(shù)定義

int AnalyzeCommandLine(char* cline)
  • cline:輸入的命令行字符串(用戶在命令行輸入的完整命令)。該字符串將會被解析為多個命令和參數(shù)。

初始化參數(shù)索引

int i = 0;
  • i:定義一個整數(shù)變量 i,用于跟蹤 argv 數(shù)組的索引位置,表示當(dāng)前解析的命令參數(shù)的位置。

使用 strtok 解析命令行

argv[i++] = strtok(cline, DELIM);

strtok(cline, DELIM)strtok 是一個字符串分割函數(shù),它通過指定的分隔符(DELIM)將 cline 字符串分割成多個子字符串。DELIM 在此代碼中定義為 " \t",即空格和制表符。

  • 第一次調(diào)用 strtok() 時,它會返回 cline 字符串中的第一個子字符串(即命令或第一個參數(shù))。返回值會存儲在 argv[i] 中。
  • 然后 i++ 使得 i 增加 1,指向下一個位置

繼續(xù)解析命令行參數(shù)

while (argv[i++] = strtok(NULL, DELIM));
  • strtok(NULL, DELIM):在第一次調(diào)用 strtok() 后,后續(xù)調(diào)用需要傳入 NULL 作為第一個參數(shù),表示繼續(xù)從上次分割的位置開始。strtok() 會繼續(xù)根據(jù)分隔符分割剩余的命令行字符串,并返回下一個子字符串。
  • 這段代碼通過 while 循環(huán)逐個提取命令行中的每個子字符串,并將其存儲到 argv[i] 中。每次調(diào)用 strtok() 后,i++i 指向下一個數(shù)組位置。

返回參數(shù)的數(shù)量

return i - 1;
  • i - 1:由于最后一次 i++ 會多加一次,因此函數(shù)返回 i - 1,即存儲在 argv 數(shù)組中的參數(shù)個數(shù)(命令行中的參數(shù)數(shù)量)。

執(zhí)行常規(guī)命令

void NormalExecl(char* _argv[])
{pid_t id = fork();if (id < 0){perror("fork");return;}else if (id == 0){execvp(_argv[0], argv);exit(EXIT_CODE);}else{int status = 0;pid_t rid = waitpid(id, &status, 0);if (id){LASTCODE = WEXITSTATUS(status);}}
}

函數(shù)定義

void NormalExecl(char* _argv[])
  • _argv[]:這是一個參數(shù)數(shù)組,用于傳遞命令及其參數(shù)。例如,_argv[0] 是命令,_argv[1] 是命令的第一個參數(shù),依此類推。

創(chuàng)建子進程

pid_t id = fork();

fork()fork() 函數(shù)用于創(chuàng)建一個新進程。它將當(dāng)前進程復(fù)制一份。新進程被稱為子進程,原始進程是父進程。

  • 如果 fork()成功,它會返回兩次:
    • 父進程:返回子進程的進程 ID(PID)。
    • 子進程:返回 0。
  • 如果 fork() 失敗,它返回負值。

錯誤處理

if (id < 0)
{perror("fork");return;
}
  • id < 0:如果 fork() 返回負值,表示創(chuàng)建子進程失敗。此時打印錯誤信息并返回。
  • perror("fork"):輸出錯誤信息,說明 fork() 失敗的原因。

子進程執(zhí)行命令

else if (id == 0)
{execvp(_argv[0], argv);exit(EXIT_CODE);
}

id == 0:這是子進程中的代碼塊。如果 fork() 返回 0,表示當(dāng)前代碼在子進程中執(zhí)行。

execvp(_argv[0], argv):子進程調(diào)用 execvp() 函數(shù)來執(zhí)行命令。execvp() 會用指定的命令替換當(dāng)前進程的映像。具體來說:

  • _argv[0] 是命令(例如 ls)。
  • argv 是命令的參數(shù)數(shù)組,其中包含命令和它的所有參數(shù)(例如 ls -l)。

exit(EXIT_CODE):如果 execvp() 失敗,子進程會退出,返回 EXIT_CODE。如果 execvp() 成功,當(dāng)前進程會被新的命令替代,exit() 不會被執(zhí)行

父進程等待子進程結(jié)束

else
{int status = 0;pid_t rid = waitpid(id, &status, 0);if (id){LASTCODE = WEXITSTATUS(status);}
}
  • else:這是父進程中的代碼塊,父進程需要等待子進程結(jié)束并獲取其退出狀態(tài)。

  • int status = 0;:定義一個變量 status 用來存儲子進程的退出狀態(tài)。

  • waitpid(id, &status, 0)

    :父進程使用 waitpid()函數(shù)等待子進程的結(jié)束。waitpid() 會阻塞父進程,直到指定的子進程結(jié)束,并返回子進程的退出狀態(tài)。

    • id:是子進程的進程 ID,表示父進程等待這個子進程。
    • &status:存儲子進程退出時的狀態(tài)信息。
    • 0:表示父進程等待子進程的退出,不對其狀態(tài)做其他操作。
  • LASTCODE = WEXITSTATUS(status):獲取子進程的退出狀態(tài)碼并存儲在 LASTCODE 中。WEXITSTATUS(status) 提取的是子進程的退出代碼。

內(nèi)建命令執(zhí)行

int BuildExec(char* _argv[], int _argc)
{if (_argc == 2 && strcmp(_argv[0], "cd") == 0){chdir(_argv[1]);getpwd();sprintf(getenv("PWD"), "%s", pwd);return 1;}else if (_argc == 2 && strcmp(_argv[0], "export") == 0){strcpy(myenv, _argv[1]);putenv(myenv);return 1;}else if (_argc == 2 && strcmp(_argv[0], "echo") == 0){if (strcmp(_argv[1], "$?")){printf("%d\n", LASTCODE);LASTCODE = 0;}else if (strcmp(_argv[1], "$")){char* val = getenv(_argv[1] + 1);printf("%s\n", val);}else{printf("%s\n", _argv[1]);}}if (strcmp(_argv[0], "ls") == 0){_argv[_argc++] = "--color";_argv[_argc] = NULL;}return 0;
}

函數(shù)定義

int BuildExec(char* _argv[], int _argc)
  • _argv[]:命令行解析后參數(shù)的數(shù)組,存儲命令及其參數(shù)。
  • _argc:命令行參數(shù)的數(shù)量。

處理 cd 命令

if (_argc == 2 && strcmp(_argv[0], "cd") == 0)
{chdir(_argv[1]);getpwd();sprintf(getenv("PWD"), "%s", pwd);return 1;
}
  • strcmp(_argv[0], "cd") == 0:檢查命令是否為 cd。如果 argv[0]"cd",則執(zhí)行以下操作。
  • chdir(_argv[1]):改變當(dāng)前工作目錄到 argv[1] 指定的路徑。
  • getpwd():調(diào)用 getpwd() 獲取新的工作目錄并更新全局變量 pwd
  • sprintf(getenv("PWD"), "%s", pwd):更新環(huán)境變量 PWD,使其反映當(dāng)前工作目錄。
  • return 1;:表示已經(jīng)處理了 cd 命令,因此直接返回,不繼續(xù)處理后面的代碼。

處理 export 命令

else if (_argc == 2 && strcmp(_argv[0], "export") == 0)
{strcpy(myenv, _argv[1]);putenv(myenv);return 1;
}
  • strcmp(_argv[0], "export") == 0:檢查命令是否為 export。如果 argv[0]"export",則執(zhí)行以下操作。
  • strcpy(myenv, _argv[1]):將 argv[1] 的值復(fù)制到 myenv 字符數(shù)組中。argv[1] 應(yīng)該是一個環(huán)境變量的設(shè)置(例如 "VAR=value")。
  • putenv(myenv):使用 putenv()myenv 中的環(huán)境變量設(shè)置添加到當(dāng)前環(huán)境中。
  • return 1;:表示已經(jīng)處理了 export 命令,直接返回。

處理 echo 命令

else if (_argc == 2 && strcmp(_argv[0], "echo") == 0)
{if (strcmp(_argv[1], "$?")){printf("%d\n", LASTCODE);LASTCODE = 0;}else if (strcmp(_argv[1], "$")){char* val = getenv(_argv[1] + 1);printf("%s\n", val);}else{printf("%s\n", _argv[1]);}
}
  • strcmp(_argv[0], "echo") == 0:檢查命令是否為 echo。如果是,繼續(xù)執(zhí)行以下代碼。
  • strcmp(_argv[1], "$?"):檢查是否要求輸出上一個命令的退出狀態(tài)碼。如果 argv[1]"$?",則輸出上一個命令的退出代碼 LASTCODE,并將 LASTCODE 重置為 0。
  • strcmp(_argv[1], "$"):檢查是否要求輸出某個環(huán)境變量的值。如果 argv[1] 是以 $ 開頭(例如 $HOME),則獲取該環(huán)境變量的值并打印。
  • printf("%s\n", _argv[1]);:如果既不是 "$?" 也不是以 $ 開頭,則直接輸出 argv[1],即用戶傳遞給 echo 的字符串。

特殊處理 ls 命令

if (strcmp(_argv[0], "ls") == 0)
{_argv[_argc++] = "--color";_argv[_argc] = NULL;
}
  • strcmp(_argv[0], "ls") == 0:檢查命令是否為 ls。如果是 ls 命令,執(zhí)行以下操作。
  • _argv[_argc++] = "--color";:給 ls 命令添加 --color 參數(shù),這樣 ls 命令輸出的文件列表會使用不同的顏色顯示(通常是通過文件類型區(qū)分)。
  • _argv[_argc] = NULL;:將數(shù)組最后一個元素設(shè)置為 NULL,確保 execvp() 在執(zhí)行時能正確處理參數(shù)數(shù)組。

返回值

return 0;
  • 如果命令不是內(nèi)建命令(cd、export、echo)或者沒有進行特殊處理(如 ls),則返回 0,表示該命令需要外部執(zhí)行。

主程序邏輯

int main()
{while (!quit){//命令行提示ineract(commondline, sizeof(commondline));//命令解析int argc = AnalyzeCommandLine(commondline);//指令解析int n = BuildExec(argv, argc);if (!n) NormalExecl(argv);}return 0;
}
  • main:主程序循環(huán),不斷提示用戶輸入命令。首先獲取并解析命令行輸入,然后判斷是否為內(nèi)建命令,若不是,則調(diào)用 NormalExecl 執(zhí)行外部命令。直到 quit 被設(shè)置為 1 時,程序結(jié)束。
http://aloenet.com.cn/news/46724.html

相關(guān)文章:

  • 自制圖片肇慶網(wǎng)站快速排名優(yōu)化
  • wordpress映射新余seo
  • 視頻解析接口網(wǎng)站怎么做百度提交網(wǎng)站
  • 怎么自己做三個一網(wǎng)站一份完整的營銷策劃書
  • 做農(nóng)產(chǎn)品的網(wǎng)站北京優(yōu)化seo排名優(yōu)化
  • 國外銷售網(wǎng)站怎樣建設(shè)免費長尾詞挖掘工具
  • 麗水專業(yè)網(wǎng)站建設(shè)哪家好抖音seo優(yōu)化
  • wordpress.conf網(wǎng)站seo優(yōu)化免費
  • 有沒有給做淘寶網(wǎng)站的中國十大網(wǎng)站有哪些
  • 做網(wǎng)站需要什么部門批準(zhǔn)重慶seo優(yōu)化效果好
  • 濟寧做企業(yè)網(wǎng)站濟南網(wǎng)站優(yōu)化排名推廣
  • 在哪里做網(wǎng)站比較好十大廣告投放平臺
  • 做平臺和獨立建網(wǎng)站綜合型b2b電子商務(wù)平臺網(wǎng)站
  • 免費的素材網(wǎng)站網(wǎng)站如何做關(guān)鍵詞優(yōu)化
  • 個人網(wǎng)站發(fā)布怎么做優(yōu)化大師官網(wǎng)入口
  • 網(wǎng)站建設(shè)總體方案設(shè)計下載優(yōu)化大師app
  • web前端工程師職業(yè)規(guī)劃seo推廣優(yōu)化的方法
  • 公司網(wǎng)站建設(shè)有什么好處2345網(wǎng)址導(dǎo)航下載
  • 網(wǎng)站建設(shè)的公司在哪找企業(yè)推廣策略
  • 做網(wǎng)站犯法嗎小廣告圖片
  • 類似網(wǎng)站的建設(shè)西安seo網(wǎng)絡(luò)優(yōu)化公司
  • 網(wǎng)站建設(shè)個人網(wǎng)站佛山網(wǎng)絡(luò)推廣哪里好
  • 網(wǎng)站備案信息傳網(wǎng)店推廣聯(lián)盟
  • wordpress 小工具 調(diào)用seo是什么崗位
  • 山東日照建設(shè)網(wǎng)站微信小程序怎么開通
  • 做藥材生意的網(wǎng)站免費下載百度app最新版本
  • 濟南網(wǎng)絡(luò)廣播電視臺北京關(guān)鍵詞優(yōu)化報價
  • 域名服務(wù)器的四種類型營口seo
  • 網(wǎng)站建設(shè)需要哪些方面愛站網(wǎng)權(quán)重查詢
  • 深圳燃氣公司地址在哪里哈爾濱seo關(guān)鍵字優(yōu)化