国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Linux一學(xué)就會——編寫自己的shell

這篇具有很好參考價(jià)值的文章主要介紹了Linux一學(xué)就會——編寫自己的shell。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

編寫自己的shell

進(jìn)程程序替換

替換原理

用fork創(chuàng)建子進(jìn)程后執(zhí)行的是和父進(jìn)程相同的程序(但有可能執(zhí)行不同的代碼分支),子進(jìn)程往往要調(diào)用一種exec函數(shù)
以執(zhí)行另一個(gè)程序。當(dāng)進(jìn)程調(diào)用一種exec函數(shù)時(shí),該進(jìn)程的用戶空間代碼和數(shù)據(jù)完全被新程序替換,從新程序的啟動(dòng)
例程開始執(zhí)行。調(diào)用exec并不創(chuàng)建新進(jìn)程,所以調(diào)用exec前后該進(jìn)程的id并未改變。

Linux一學(xué)就會——編寫自己的shell

替換函數(shù)

其實(shí)有幾種以exec開頭的函數(shù),統(tǒng)稱exec函數(shù):

#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ...,char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);

解釋
exec是函數(shù)替換的開頭,后面跟的都是多加的功能:
l:list的簡寫,表示參數(shù)采用列表。
p:path的簡寫,就是自動(dòng)搜索并添加環(huán)境變量??梢允褂铆h(huán)境變量PATH,無需寫全路徑。
v:vector的簡寫,是可以用參數(shù)數(shù)組。
e:environment的簡寫,就是環(huán)境變量。就是帶e都要自己組裝環(huán)境變量,而且是數(shù)組形式傳入。

這些函數(shù)如果調(diào)用成功則加載新的程序從啟動(dòng)代碼開始執(zhí)行,不再返回。
如果調(diào)用出錯(cuò)則返回-1
所以exec函數(shù)只有出錯(cuò)的返回值而沒有成功的返回值。

Linux一學(xué)就會——編寫自己的shell
可變參數(shù)
我們剛剛可以看到int execl(const char *path, const char *arg, …);
比如:

int func(int, ... )  {
   .
   .
   .
}
 
int main() {
   func(2, 2, 3);
   func(3, 2, 3, 4);
}

函數(shù) func() 最后一個(gè)參數(shù)寫成省略號,即三個(gè)點(diǎn)號(…),省略號之前的那個(gè)參數(shù)是 int,代表了要傳遞的可變參數(shù)的總數(shù)。為了使用這個(gè)功能,您需要使用 stdarg.h 頭文件,該文件提供了實(shí)現(xiàn)可變參數(shù)功能的函數(shù)和宏。具體步驟如下:
定義一個(gè)函數(shù),最后一個(gè)參數(shù)為省略號,省略號前面可以設(shè)置自定義參數(shù)。
在函數(shù)定義中創(chuàng)建一個(gè) va_list 類型變量,該類型是在 stdarg.h 頭文件中定義的。
使用 int 參數(shù)和 va_start() 宏來初始化 va_list 變量為一個(gè)參數(shù)列表。宏 va_start() 是在 stdarg.h 頭文件中定義的。
使用 va_arg() 宏和 va_list 變量來訪問參數(shù)列表中的每個(gè)項(xiàng)。
使用宏 va_end() 來清理賦予 va_list 變量的內(nèi)存。

也就是說可變參數(shù)是放在傳入?yún)?shù)最后,放在中間必須在輸入結(jié)束之后再輸入一個(gè)NULL,而且可變參數(shù)和前面放的參數(shù)類型一致。
exec調(diào)用舉例:

#include <unistd.h>
int main()
{
char *const argv[] = {"ps", "-ef", NULL};
char *const envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};
execl("/bin/ps", "ps", "-ef", NULL);
// 帶p的,可以使用環(huán)境變量PATH,無需寫全路徑
execlp("ps", "ps", "-ef", NULL);
// 帶e的,需要自己組裝環(huán)境變量
execle("ps", "ps", "-ef", NULL, envp);
execv("/bin/ps", argv);
// 帶p的,可以使用環(huán)境變量PATH,無需寫全路徑
execvp("ps", argv);
// 帶e的,需要自己組裝環(huán)境變量
execve("/bin/ps", argv, envp);
exit(0);
}

事實(shí)上,只有execve是真正的系統(tǒng)調(diào)用,其它五個(gè)函數(shù)最終都調(diào)用 execve,所以execve在man手冊 第2節(jié),其它函數(shù)在
man手冊第3節(jié)。這些函數(shù)之間的關(guān)系如下圖所示。

Linux一學(xué)就會——編寫自己的shell

開始寫自己的shell

用下圖的時(shí)間軸來表示事件的發(fā)生次序。其中時(shí)間從左向右。shell由標(biāo)識為sh的方塊代表,它隨著時(shí)間的流逝從左
向右移動(dòng)。shell從用戶讀入字符串"ls"。shell建立一個(gè)新的進(jìn)程,然后在那個(gè)進(jìn)程中運(yùn)行l(wèi)s程序并等待那個(gè)進(jìn)程結(jié)
束。Linux一學(xué)就會——編寫自己的shell
每當(dāng)輸入一個(gè)命令時(shí),bash就會創(chuàng)建一個(gè)子進(jìn)程來實(shí)現(xiàn)的要的命令進(jìn)程,上述就是ls,等待子進(jìn)程退出,主進(jìn)程繼續(xù)等待命令輸入和讀取命令,再創(chuàng)建子進(jìn)程等…

第一步創(chuàng)建一個(gè)界面然后讓他一直死循環(huán)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include  <ctype.h>

#define MAX_CMD 1024
char command[MAX_CMD];
int myshell_face()
{
    memset(command, 0x00, MAX_CMD);
    printf("[Tomshell$]#");
    fflush(stdout);
    if (scanf("%[^\n]%*c", command) == 0)
    {
        getchar();
        return -1;
    }
    return 0;
}
int main(int argc, char *argv[])
{
    while (1) // shell主循環(huán)
    {
        myshell_face();    
    }
    return 0;
}

當(dāng)然這個(gè)界面是可以輸入命令的,但是你怎么輸入都沒用。

接下來是解析你輸入的命令了。
把剛剛輸入的命令行分析出來,比如遇到空格就會再次push_back命令行數(shù)組,當(dāng)有空格就跳過空格,知道遇到NULL為止。

char **do_parse(char *command)
{
    int argc = 0;
    static char *argv[32];
    char *ptr = command;
    while (*ptr != '\0')
    {
        if (!isspace(*ptr))//如果不是空格就一直讀取命令,直到遇到空格
        {
            argv[argc++] = ptr;
            while ((!isspace(*ptr)) && (*ptr) != '\0')//#include  <ctype.h>   isspace檢測是否遇到空格
            {
                ptr++;              //如果不是空格就一直讀取命令,直到遇到空格
            }
        }
        else
        {
            while (isspace(*ptr))//如果命令前幾個(gè)是空格就消除空格
            {
                //*ptr = '\0';//這句就不用加了
                ptr++;
            }
        }
    }
    argv[argc] = NULL;
    return argv;
}

解析完之后返回的是命令行參數(shù)數(shù)組指針

開始創(chuàng)建子進(jìn)程并且用execvp替換子進(jìn)程。

int do_exec(char *command)//進(jìn)程替換函數(shù)=》用的就是exec
{
    char **argv = {NULL};
    int pid = fork(); // 一切形式的進(jìn)程都讓子進(jìn)程去辦,子進(jìn)程就是白手套。
    if (pid == 0)
    {
        argv = do_parse(command);
        if (argv[0] == NULL)
        {
            exit(-1);
        }
        execvp(argv[0], argv); // 進(jìn)程替換函數(shù),可以添加環(huán)境變量p(path),參數(shù)格式是數(shù)組v(vector)
    }                          // 可以把exec當(dāng)作call(goto)函數(shù),exit當(dāng)作return函數(shù)。
    else
    {
        waitpid(pid, NULL, 0);
    }
    return 0;
}

這樣就可以在子進(jìn)程實(shí)現(xiàn)命令行進(jìn)程了。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include  <ctype.h>

#define MAX_CMD 1024
char command[MAX_CMD];
int myshell_face()
{
    memset(command, 0x00, MAX_CMD);
    printf("[Tomshell$]#");
    fflush(stdout);
    if (scanf("%[^\n]%*c", command) == 0)
    {
        getchar();
        return -1;
    }
    return 0;
}
char **do_parse(char *command)
{
    int argc = 0;
    static char *argv[32];
    char *ptr = command;
    while (*ptr != '\0')
    {
        if (!isspace(*ptr))//如果不是空格就一直讀取命令,直到遇到空格
        {
            argv[argc++] = ptr;
            while ((!isspace(*ptr)) && (*ptr) != '\0')//#include  <ctype.h>   isspace檢測是否遇到空格
            {
                ptr++;              //如果不是空格就一直讀取命令,直到遇到空格
            }
        }
        else
        {
            while (isspace(*ptr))//如果命令前幾個(gè)是空格就消除空格
            {
                //*ptr = '\0';//這句就不用加了
                ptr++;
            }
        }
    }
    argv[argc] = NULL;
    return argv;
}
int do_exec(char *command)//進(jìn)程替換函數(shù)=》用的就是exec
{
    char **argv = {NULL};
    int pid = fork(); // 一切形式的進(jìn)程都讓子進(jìn)程去辦,子進(jìn)程就是白手套。
    if (pid == 0)
    {
        argv = do_parse(command);
        if (argv[0] == NULL)
        {
            exit(-1);
        }
        execvp(argv[0], argv); // 進(jìn)程替換函數(shù),可以添加環(huán)境變量p(path),參數(shù)格式是數(shù)組v(vector)
    }                          // 可以把exec當(dāng)作call(goto)函數(shù),exit當(dāng)作return函數(shù)。
    else
    {
        waitpid(pid, NULL, 0);
    }
    return 0;
}
int main(int argc, char *argv[])
{
    while (1) // shell主循環(huán)
    {
        if (myshell_face() < 0)
            continue;
        do_exec(command);
    }
    return 0;
}

最終成果:
Linux一學(xué)就會——編寫自己的shell文章來源地址http://www.zghlxwxcb.cn/news/detail-435248.html

到了這里,關(guān)于Linux一學(xué)就會——編寫自己的shell的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • macOS安裝Python&&Pycharm詳解!保姆級教程,一學(xué)就會!

    macOS安裝Python&&Pycharm詳解!保姆級教程,一學(xué)就會!

    有需要打包好的PycharmPython激活碼和安裝包也可直接掃下方 首先登陸python官網(wǎng):www.python.org/ 點(diǎn)擊Download按鈕,選擇自己電腦的系統(tǒng),有些時(shí)候網(wǎng)頁可以自動(dòng)識別 下載最新的python 版本號是隨著版本發(fā)展不斷演進(jìn),上圖中顯示3.12.2。但都是python3 等待下載完成,打開文件,一直點(diǎn)

    2024年04月25日
    瀏覽(19)
  • 【一學(xué)就會】Facebook臉書視頻下載一秒保存手機(jī)

    【一學(xué)就會】Facebook臉書視頻下載一秒保存手機(jī)

    Facebook作為一家全球知名的社交媒體平臺和在線社交網(wǎng)絡(luò)服務(wù)公司,提供了一個(gè)在線平臺,使用戶分享照片、視頻、狀態(tài)更新和鏈接等內(nèi)容,然而,令人遺憾的是,F(xiàn)acebook沒有為用戶提供直接將照片和視頻保存到本地的功能,因此,無法保存自己喜歡的視頻圖片。 今天在這里

    2024年02月04日
    瀏覽(15)
  • postman導(dǎo)入請求到j(luò)meter進(jìn)行簡單壓測,開發(fā)同學(xué)一學(xué)就會

    這個(gè)事情也是最近做的,因?yàn)榫€上nginx被我換成了openresty,然后接入層服務(wù)也做了較大改動(dòng),雖然我們這個(gè)app(內(nèi)部辦公類)并發(fā)不算高,但好歹還是壓測一下,上線時(shí)心里也穩(wěn)一點(diǎn)。 于是用jmeter簡單壓測下看看,這里記錄一下。 這次也就找了幾個(gè)接口來壓:登錄接口、登錄

    2024年04月25日
    瀏覽(54)
  • 詳解二分算法(一學(xué)就懂,一寫就會)

    詳解二分算法(一學(xué)就懂,一寫就會)

    小明:\\\"小張,我問你一個(gè)問題:在1,3,5,6,7,9這些數(shù)中5在那個(gè)位置?\\\" 小張:\\\"這還不簡單,5在第三個(gè)位置!我是按順序來找的:1,3,5。\\\" 小明:\\\"那我告訴你1~100這些數(shù),讓你找其中100這個(gè)數(shù),你也從1~100來一個(gè)一個(gè)數(shù)嗎?\\\" 小張:\\\"那我會從100~1來數(shù)。\\\" 小明:\\\"那如果你是一個(gè)機(jī)器

    2024年02月16日
    瀏覽(16)
  • RocketMQ-dockefile制作鏡像過程(一學(xué)就廢)

    RocketMQ-dockefile制作鏡像過程(一學(xué)就廢)

    下載rockermq包: https://rocketmq.apache.org/zh/download/ source開源和binary二進(jìn)制安裝 開始編寫rmqnamesrv的dockerfile 開始編寫rmqbroker的dockerfile 生成鏡像 查看我實(shí)驗(yàn)生成的images 命令啟動(dòng)rockermq服務(wù) 這里NAMESRV_ADDR=1.1.1.1:9876是需要指定你安裝的rmqnamesrv的ip+端口,-v掛載的日志以及對于的配置

    2024年02月11日
    瀏覽(22)
  • msf--Linux反彈shell--一看就會的實(shí)驗(yàn)

    msf--Linux反彈shell--一看就會的實(shí)驗(yàn)

    環(huán)境如下 vps :Linux ubuntu 4.15.0-180-generic (已經(jīng)打開8989端口) win:Windows Feature Experience Pack 120.2212.4180.0(可以隨意) 靶機(jī):Linux ubuntu 4.18.0-25-generic 過程如下 1.在vps里面生成木馬 ?msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=xx.xx.xx.xx LPORT=8989 -f elf asd ?2.將木馬下載到本機(jī)桌面 sz a

    2023年04月13日
    瀏覽(30)
  • Linux shell腳本編寫

    Linux shell腳本編寫

    一、常用shell腳本指令 echo: 輸出指定的文本或變量值到標(biāo)準(zhǔn)輸出。 read: 從標(biāo)準(zhǔn)輸入讀取用戶輸入,并將其保存到指定的變量中。 if: 執(zhí)行條件語句,如果滿足指定條件則執(zhí)行特定操作,否則執(zhí)行其他操作。 for: 循環(huán)執(zhí)行特定操作,每次迭代更新變量值。 while: 循環(huán)執(zhí)行

    2024年02月16日
    瀏覽(30)
  • Linux編寫簡易shell

    Linux編寫簡易shell

    思路:? ? ? 所以要寫一個(gè)shell,需要循環(huán)以下過程:? 獲取命令行 解析命令行 建立一個(gè)子進(jìn)程(fork) 替換子進(jìn)程(execvp) 父進(jìn)程等待子進(jìn)程退出(wait) 實(shí)現(xiàn)代碼:? ????????以上就是本文的全部內(nèi)容,如果對你有幫助,歡迎點(diǎn)贊收藏轉(zhuǎn)發(fā)評論!?

    2024年01月20日
    瀏覽(18)
  • Linux自定義shell編寫

    Linux自定義shell編寫

    經(jīng)過了創(chuàng)建進(jìn)程,終止進(jìn)程,進(jìn)程等待和進(jìn)程程序替換之后, 我們就可以借助這些知識實(shí)現(xiàn)一個(gè)簡單的shell命令行解釋器了 溫馨提示: 建議大家自己寫一遍,這些代碼分塊之后每一個(gè)函數(shù)都很簡單, 不過實(shí)現(xiàn)過程中可能會有各種各樣非常細(xì)枝末節(jié)的地方被我們所忽視 因此可能會發(fā)生

    2024年02月04日
    瀏覽(17)
  • 【Linux】編寫一個(gè) shell 腳本&執(zhí)行

    在Linux中編寫和執(zhí)行腳本相對簡單。下面是一個(gè)基本的步驟指南,幫助你創(chuàng)建一個(gè)簡單的bash腳本并運(yùn)行它: 1. 創(chuàng)建腳本文件 首先,你需要使用文本編輯器創(chuàng)建一個(gè)新的文件。這個(gè)文件通常會有 .sh 的擴(kuò)展名,以表明它是一個(gè)shell腳本。例如,你可以創(chuàng)建一個(gè)名為 myscript.sh 的文

    2024年04月26日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包