99精品久久精品一区二区-亚洲熟妇无码?v在线播放-日本国产精品无码字幕在线观看-久久久亚洲永夜AV-亚洲一级无码一区二区一-免费国产成高清人在线视频-中文字幕乱码免费观看-国产毛片精品妇女久久久

ARTICLE DETAIL

資訊詳情

深耕商務建站與企業(yè)官網(wǎng)運營的一線實戰(zhàn)洞察。

手寫自定義Shell:從fork/exec到管道重定向的Linux進程實戰(zhàn)

手寫自定義Shell:從fork/exec到管道重定向的Linux進程實戰(zhàn) 1. 為什么要在2025年親手寫一個Shell這個項目比你想的更值錢先別急著關頁面。我知道你的第一反應是Shell不是現(xiàn)成的嗎Bash、Zsh、Fish隨便挑一個都比自己寫的強我干嘛要自討苦吃這個反應沒錯但恰恰是問題所在。現(xiàn)成的Shell把你該學的東西都藏起來了。你在終端里敲ls -l | grep txt的時候Bash替你做了三件事解析字符串、創(chuàng)建管道、拉起子進程。這三件事每一個都是操作系統(tǒng)核心機制的實戰(zhàn)考點而你平時根本看不見它們。我見過太多人Linux命令敲得飛起但一問fork()和exec()的區(qū)別就卡殼能寫出幾百行的Shell腳本卻不理解為什么管道兩端的命令是“同時”運行的。倒不是說他們笨而是工具太好的時候人對底層機制會失去感知。這就跟開自動擋開久了不會開手動擋一樣不是技術問題是習慣問題。自定義Shell這個項目本質(zhì)上就是把你平時用的黑盒打開讓你看看里面是什么。你不需要做出一個能和Bash抗衡的產(chǎn)品你只需要做出一個能跑ls、cd、cat file | grep foo、./program out.txt的“玩具”——但這趟走下來你對Linux進程模型、文件描述符、字符串處理的理解會比你讀三章APUE來得扎實。而且實用性也很強。很多公司面試會問“設計一個迷你Shell”或者讓你在紙上寫fork exec wait的組合代碼。你親手寫過一遍這種題就是送分題。退一步說就算不為了面試理解Shell的工作方式對你寫配置腳本、排查啟動問題、理解Docker容器的進程行為都有直接幫助——因為你終于知道那些“神奇”的操作底下到底發(fā)生了什么。下面我直接把這套實現(xiàn)拆開講從項目結(jié)構(gòu)、核心機制到具體代碼、踩坑記錄一條線走完。2. 動手前的核心知識儲備進程模型、系統(tǒng)調(diào)用與解析器設計的底層邏輯寫Shell之前必須先建立三個底層認知。這三點如果不提前搞清楚寫出來的東西大概率是“看起來像Shell跑起來全是病”。2.1 進程模型Shell其實是個“包工頭”Linux下的進程模型一句話概括就是進程是“復制”出來的不是“創(chuàng)建”出來的。所有用戶態(tài)進程都是從一個叫init的祖先進程一路fork()復制出來的。關鍵認知是一個程序跑起來之后你通常有兩個實體——父進程和子進程。父進程負責“管理”子進程負責“干活”。Shell就是父親的典型代表它接收你輸入的命令然后fork()出一個子進程再在子進程里用exec()把命令真正換上去。打個比方。Shell是包工頭你讓他蓋一棟樓執(zhí)行命令他不會自己上腳手架而是打電話叫一隊工人fork()一個新進程然后告訴工人具體干什么活exec()把程序加載進來。包工頭自己在旁邊蹲著等工人干完wait()好匯報給你。這跟我們平時跑程序的感覺完全不一樣。我們直覺上覺得“程序是被操作系統(tǒng)創(chuàng)建出來的”但Linux底下的語言是先復制一份當前狀態(tài)再替換成新程序。這兩個步驟必須拆開理解否則你會對整個Shell的實現(xiàn)邏輯產(chǎn)生疑惑。2.2 三大系統(tǒng)調(diào)用fork、exec、wait這是Shell的基石必須吃透。fork()調(diào)用一次返回兩次。一次在父進程里返回子進程的PID一次在子進程里返回0。返回值是負則說明創(chuàng)建失敗。這段代碼pid_t pid fork(); if (pid 0) { // 子進程這里繼續(xù)跑的是從父進程復制過來的代碼副本 } else if (pid 0) { // 父進程pid 就是子進程的進程ID } else { perror(fork); }很多人不理解“返回兩次”是怎么回事。換個說法fork()完成那一刻系統(tǒng)里憑空多了一個進程這個進程和父進程幾乎一模一樣連程序計數(shù)器PC的位置都一樣。也就是說子進程從fork()返回的那一行開始繼續(xù)執(zhí)行同一份代碼。唯一能區(qū)分兩人的就是返回值——父進程拿到的是子進程的PID子進程拿到的是0。exec()注意它不是函數(shù)而是一族函數(shù)——execl、execv、execvp等等。它們的作用是一個進程把自己“換掉”把當前進程的代碼段、數(shù)據(jù)段、棧全部替換成新程序的然后從頭開始跑新程序。成功的話不會返回失敗才返回 -1。我們后面統(tǒng)一用execvp()因為它的第二個參數(shù)直接接受一個字符串數(shù)組argv形式對解析命令行特別方便。wait()/waitpid()父進程調(diào)用這個就會阻塞直到某個子進程結(jié)束。這個“阻塞”很重要——Shell必須等命令執(zhí)行完才能顯示下一行提示符這跟你在終端里的直覺體驗一致。三者合起來的完整流程父進程讀入一行命令fork()出子進程子進程調(diào)用execvp()變成那條命令本身父進程調(diào)用waitpid()等子進程退出子進程退出后父進程打印提示符繼續(xù)讀下一條命令。這個循環(huán)永遠不會變Shell的一切都是圍繞它展開的。2.3 解析器設計把“字符串”變成“參數(shù)數(shù)組”Shell讀到的是一行字符串比如ls -l /home/user。但execvp()需要的是char *argv[] {ls, -l, /home/user, NULL};所以你要做的是把char *line變成char **args。這個過程叫命令行解析是整個項目里最考驗“耐煩心”的部分——它不涉及什么高深算法但全是邊界條件。一個常見的誤區(qū)是別只用空格拆分。因為Shell命令里可以有引號echo hello world和轉(zhuǎn)義echo hello\ world粗暴按空格拆會把hello world拆成兩個參數(shù)。我們第一版可以不管引號但你要知道這個邊界存在否則后續(xù)擴展時容易翻車。我會用strsep()這個不太常見的函數(shù)來做拆分原因后面正文里說。它比strtok()安全——strtok()內(nèi)部有靜態(tài)變量線程不友好而且會把連續(xù)分隔符跳過有時候這不是你想要的。解析器可以分兩步走先用一個函數(shù)把整行命令按空白拆成獨立單詞再把結(jié)果整理成NULL結(jié)尾的指針數(shù)組。任何哈希、樹結(jié)構(gòu)、復雜狀態(tài)機在這個項目里都是過度設計——你需要的只是循環(huán)、指針、和一點點耐心。3. 第一個能跑的Shell骨架從main函數(shù)到循環(huán)框架好基礎打完了開始寫代碼。我不會一次性給你一個900行的完整項目而是從最小的骨架開始一步步長出一個能用的Shell。3.1 用getline()讀入命令比你想的要注意更多細節(jié)讀取命令行的標準做法是getline()它自動管理緩沖區(qū)比你用fgets()滿省心得多。核心代碼#define _GNU_SOURCE #include stdio.h #include stdlib.h #include string.h char *line NULL; size_t bufsize 0; ssize_t nread getline(line, bufsize, stdin); if (nread -1) { // EOF 或出錯 free(line); exit(0); } // 去掉末尾換行符 line[strcspn(line, \n)] \0;三個易踩的坑坑1getline()返回的是ssize_t不是int。無符號類型和有符號類型比較時會有隱式轉(zhuǎn)換問題編譯器會報警告。養(yǎng)成用ssize_t的習慣???去掉換行符千萬別用strlen(line) - 1。如果文件最后一行沒有換行符strlen減一就把合法字符刪掉了。用strcspn(line, \n)找到換行符的位置安全得多???命令行過長時getline()會自動擴容緩沖區(qū)不用你操心。但這也意味著你必須free()否則每次循環(huán)都泄漏一段內(nèi)存。別偷懶。3.2 主循環(huán)框架“讀命令 - 解析 - 執(zhí)行 - 等待”的無限循環(huán)Shell的本質(zhì)就是一個死循環(huán)退出條件只有兩個用戶敲exit或者輸入流遇到EOF比如按CtrlD。int main(void) { char *line NULL; size_t bufsize 0; ssize_t nread; while (1) { printf(mysh ); fflush(stdout); // 一定要有 nread getline(line, bufsize, stdin); if (nread -1) { printf(\n); break; // EOF 退出 } line[strcspn(line, \n)] \0; // 空命令直接跳過 if (strlen(line) 0) continue; char **args parse_command(line); if (args[0] NULL) { free(args); continue; } // 檢查是不是內(nèi)建命令是的話直接執(zhí)行不是再fork if (is_builtin(args[0])) { run_builtin(args); } else { run_external(args); } free(args); } free(line); return 0; }這段代碼展示了整體骨架。注意fflush(stdout)這一行——沒有它提示符可能不會立即顯示尤其在管道或腳本環(huán)境下。這是初學者最容易忽略的細節(jié)之一后面會說更多。3.3parse_command()我為什么推薦strsep()而不是strtok()解析函數(shù)要把ls -l /home變成{ls, -l, /home, NULL}。我推薦用strsep()char **parse_command(char *line) { int bufsize 64; int index 0; char **args malloc(bufsize * sizeof(char *)); char *token; if (!args) { perror(malloc); exit(EXIT_FAILURE); } char *rest line; while ((token strsep(rest, \t\r\n)) ! NULL) { if (*token \0) continue; // 跳過連續(xù)空白 args[index] token; index; if (index bufsize) { bufsize 64; args realloc(args, bufsize * sizeof(char *)); if (!args) { perror(realloc); exit(EXIT_FAILURE); } } } args[index] NULL; return args; }為什么不用strtok()三個理由每一個都夠你在生產(chǎn)環(huán)境里吃一次虧1. 線程安全。strtok()內(nèi)部維護了一個靜態(tài)變量來保存剩余字符串位置多個線程同時調(diào)用會串數(shù)據(jù)。Shell雖然是單線程的但這個壞習慣不值得養(yǎng)成。strsep()用局部變量rest手動控制。2. 連續(xù)空白符的處理粒度不一樣。strtok()默認把連續(xù)分隔符當成一個strsep()會返回空字符串需要你手動跳過。看起來是多寫了一行但給了你更多控制權(quán)。3. 解析失敗時便于排查。因為你每一步都在自己的局部變量上進行斷點調(diào)試時可以看到全部中間狀態(tài)。這里有個關鍵細節(jié)args數(shù)組里的指針直接指向原line字符串里的位置。也就是說解析沒有strdup沒有新分配內(nèi)存只是把原來的空格替換成\0然后記錄每個單詞的起點。這樣解析速度極快但代價是——你必須保證line在args使用期間不被釋放或修改。在我們的主循環(huán)里args在run_external()返回后才被釋放而execvp()在子進程里已經(jīng)完成加載所以沒問題。3.4 執(zhí)行外部命令fork execvp waitpid 的標準模板run_external()是核心中的核心void run_external(char **args) { pid_t pid fork(); if (pid -1) { perror(fork); return; } if (pid 0) { // 子進程直接替換成目標程序 if (execvp(args[0], args) -1) { perror(execvp); exit(EXIT_FAILURE); // 必須exit否則會繼續(xù)跑父進程的循環(huán) } } else { // 父進程等待子進程完成 int status; if (waitpid(pid, status, 0) -1) { perror(waitpid); return; } // 可以在這里檢查 status判斷命令是否正常退出 } }這段代碼你倒背如流也不過分。但我必須強調(diào)一個致命細節(jié)子進程里調(diào)用execvp()失敗后必須立即exit(EXIT_FAILURE)。如果漏掉這行子進程就會繼續(xù)往下執(zhí)行進入父進程的循環(huán)邏輯然后子進程也跑去讀命令、fork進程——你就獲得了一群裂變出來的Shell。這是新手最容易犯、后果最嚴重的錯誤。在子進程分支里永遠記住exec一族函數(shù)成功就不返回失敗也必須立即退出。還有一點execvp()找可執(zhí)行文件依賴環(huán)境變量PATH。它內(nèi)部會自動搜索PATH目錄下的可執(zhí)行文件。你傳入的args[0]如果是簡單的ls它就會去/usr/bin等目錄找。如果想執(zhí)行當前目錄下的程序用戶必須輸入./a.out像真正的Shell一樣。4. 內(nèi)建命令的處理為什么必須自己實現(xiàn)cd、exit、echo你可能想問cd不也是一個可執(zhí)行文件嗎我直接execvp(cd, args)不就行了不行。原因得從進程模型里找——你還記得吧子進程是父進程的“復制品”子進程里改了什么都不會影響父進程。cd的本質(zhì)是改變進程的當前工作目錄這屬于進程自身狀態(tài)。如果你fork()一個子進程去執(zhí)行cd子進程的工作目錄變了但父進程Shell本體的工作目錄紋絲不動。等你回到主循環(huán)打出下一個提示符目錄還是原來那個。這就是“內(nèi)建命令必須由Shell進程自己執(zhí)行”的根本原因。內(nèi)核態(tài)的表現(xiàn)也是如此改變工作目錄的是chdir()系統(tǒng)調(diào)用它只對發(fā)起調(diào)用的進程起作用。沒有一條路能讓子進程去改父進程的工作目錄某些調(diào)試器玩法另說但那不是普通命令的路徑。4.1cd的實現(xiàn)比你想的復雜一點點int mysh_cd(char **args) { if (args[1] NULL) { // 沒有參數(shù)回到主目錄 const char *home getenv(HOME); if (home NULL) { fprintf(stderr, mysh: cd: HOME not set\n); return 1; } if (chdir(home) ! 0) { perror(mysh: cd); return 1; } } else { if (chdir(args[1]) ! 0) { perror(mysh: cd); return 1; } } return 0; }兩個容易忽略的細節(jié)第一cd不帶參數(shù)時應該回到HOME目錄。這是POSIX標準約定也是用戶在交互式Shell中的直覺。別嫌麻煩加上去。第二參數(shù)多于一個時怎么處理標準cd只接受一個參數(shù)加上可選的-P/-L標志。我們做個簡化版只取args[1]多余參數(shù)報錯即可。4.2exit的實現(xiàn)要有返回值意識int mysh_exit(char **args) { if (args[1] ! NULL) { // 如果帶了退出碼參數(shù)就解析它 int code atoi(args[1]); exit(code); } exit(0); }注意這里有個小訣竅你可以在主循環(huán)里讓run_builtin()返回一個特殊值提示“該退出Shell了”而不是在mysh_exit()里直接exit()。這樣設計更靈活以后你想加“退出前保存歷史記錄”“打印最后一條統(tǒng)計信息”之類的功能就還有機會攔截。直接exit()相當于把后門焊死了。4.3echo的一個隱藏問題參數(shù)已經(jīng)解析好了要不要處理引號echo在處理參數(shù)時要多個心眼。我們已經(jīng)說了第一版解析器不會處理引號所以用戶輸入echo hello world時parse_command()會拆成{echo, \hello, world\, NULL}。那echo打印出來就是hello world帶引號的兩個單詞。這是整個項目最折磨人的部分也最能體現(xiàn)“做玩具和做產(chǎn)品的差別”。如果我們想支持引號就得升級解析器讓它識別...內(nèi)的空格不算分隔符。但注意優(yōu)先級先讓核心跑起來再考慮完善。第一版的echo就是這么簡單int mysh_echo(char **args) { for (int i 1; args[i] ! NULL; i) { printf(%s, args[i]); if (args[i1] ! NULL) printf( ); } printf(\n); return 0; }等核心功能都跑通了你還想支持引號我們再單獨寫一個quote_aware_parse()替換掉parse_command()。這樣項目迭代順序清晰每一輪都有可驗證的成果。4.4 內(nèi)建命令的狀態(tài)管理用一個字符串數(shù)組和函數(shù)指針表內(nèi)建命令多了以后代碼別寫成一大串if-else。用表驅(qū)動的方法更清爽struct builtin_t { char *name; int (*func)(char **args); }; struct builtin_t builtins[] { {cd, mysh_cd}, {exit, mysh_exit}, {echo, mysh_echo}, {help, mysh_help}, // 可以自己加一個幫助命令 {NULL, NULL} }; int is_builtin(char *cmd) { for (int i 0; builtins[i].name ! NULL; i) { if (strcmp(cmd, builtins[i].name) 0) return 1; } return 0; } int run_builtin(char **args) { for (int i 0; builtins[i].name ! NULL; i) { if (strcmp(args[0], builtins[i].name) 0) { return builtins[i].func(args); } } fprintf(stderr, mysh: %s: not a builtin\n, args[0]); return 1; }以后想加pwd、export、history各自寫個函數(shù)然后在表里加一行就行主循環(huán)代碼一行不用改。代碼要寫到“加功能比加分支更容易”的程度這才叫好的項目結(jié)構(gòu)。5. 重定向與管道讓命令真正組合起來的Unix哲學外殼跑通了但現(xiàn)在的Shell是“單命令執(zhí)行器”。你沒法寫出ls out.txt也沒法寫出cat file | grep foo。這兩種操作涉及操作系統(tǒng)里最核心的一個概念文件描述符。5.1 文件描述符與重定向的底層原理一切都是文件Linux下“一切都是文件”進程通過文件描述符整數(shù)編號訪問文件。0號是標準輸入1號是標準輸出2號是標準錯誤。鍵盤輸入、屏幕輸出本質(zhì)上都是通過這幾個文件描述符完成的。ls out.txt的意思就是把1號文件描述符指向的文件換成out.txt。這樣ls寫往標準輸出的內(nèi)容就進了文件。實現(xiàn)用的系統(tǒng)調(diào)用是dup2()int fd open(out.txt, O_WRONLY | O_CREAT | O_TRUNC, 0644); dup2(fd, STDOUT_FILENO); // 把標準輸出重定向到 fd close(fd);dup2(fd, STDOUT_FILENO)的意思是“把fd復制到1號位置”即讓1號描述符指向fd指向的那個打開文件描述。之后printf輸出的內(nèi)容就去文件里了。注意dup2()之后必須close(fd)——因為1號和fd都指向同一個文件表項你只需要保留1號就夠了多一個引用只會造成資源泄漏。5.2 支持、、的解析三個運算符三種打開方式修改解析邏輯的步驟掃描args數(shù)組看有沒有、、或2之類的標記標記后面的那個參數(shù)就是文件名在子進程執(zhí)行execvp()之前先打開文件調(diào)用dup2()重定向然后執(zhí)行命令args里要把重定向操作符和文件名剔除只留下真正的命令參數(shù)。實現(xiàn)上我建議在run_external()里增加一個預處理步驟void run_external(char **args) { pid_t pid fork(); if (pid 0) { // 子進程 for (int i 0; args[i] ! NULL; i) { if (strcmp(args[i], ) 0) { int fd open(args[i1], O_WRONLY | O_CREAT | O_TRUNC, 0644); dup2(fd, STDOUT_FILENO); close(fd); args[i] NULL; // 截斷命令參數(shù) break; } // 同理處理 和 } execvp(args[0], args); perror(execvp); exit(EXIT_FAILURE); } // 父進程照舊 }有一個必須想清楚的細節(jié)為什么重定向在子進程里做而不在父進程里做因為在父進程里改文件描述符會影響到下一輪主循環(huán)而且重定向是“這一次命令”的行為不是Shell自己的行為。所以必須在fork()之后、execvp()之前在子進程內(nèi)部完成重定向——此時子進程有獨立的文件描述符表隨便改都不影響父進程Shell。用O_RDONLY用O_WRONLY | O_CREAT | O_APPEND。三個操作符映射到三種打開方式記住這個表就行。5.3 管道的實現(xiàn)|操作符的本質(zhì)是把一個進程的輸出接到另一個進程的輸入管道比重定向更微妙。ls | grep txt的邏輯是創(chuàng)建管道pipe()系統(tǒng)調(diào)用得到一個讀端和一個寫端ls的標準輸出重定向到寫端grep的標準輸入重定向到讀端兩個進程可以同時運行數(shù)據(jù)從ls流往grep。代碼實現(xiàn)void run_pipeline(char **left_args, char **right_args) { int pipefd[2]; pipe(pipefd); // pipefd[0] 讀端, pipefd[1] 寫端 pid_t p1 fork(); if (p1 0) { // 左命令輸出到寫端 close(pipefd[0]); // 用不到讀端 dup2(pipefd[1], STDOUT_FILENO); close(pipefd[1]); execvp(left_args[0], left_args); perror(execvp left); exit(EXIT_FAILURE); } pid_t p2 fork(); if (p2 0) { // 右命令從讀端讀入 close(pipefd[1]); // 用不到寫端 dup2(pipefd[0], STDIN_FILENO); close(pipefd[0]); execvp(right_args[0], right_args); perror(execvp right); exit(EXIT_FAILURE); } // 父進程關閉兩端 close(pipefd[0]); close(pipefd[1]); waitpid(p1, NULL, 0); waitpid(p2, NULL, 0); }這里有幾個反直覺的點我當年全踩過第一父子進程必須關掉沒用的一端。假設ls進程沒關讀端grep進程沒關寫端會發(fā)生什么管道還有“活著的引用”grep等待輸入時系統(tǒng)不會發(fā)EOF于是grep永遠等下去整個管道掛死。必須讓管道兩端的進程都關掉不需要的那一端才能保證數(shù)據(jù)流結(jié)束時有EOF信號。第二管道和重定向可以疊加嗎可以但順序很重要。ls | grep foo out.txt的結(jié)構(gòu)是“左命令輸出進管道右命令的輸出進文件”。實現(xiàn)時先按管道創(chuàng)建子進程然后在右子進程里先做標準輸入的重定向管道讀端再處理重定向。這個組合邏輯會越寫越復雜所以更優(yōu)雅的方案是逐步擴展成“命令表”command table結(jié)構(gòu)這里先不展開。第三管道的進程是同時還是先后創(chuàng)建記住一個原則先創(chuàng)建所有進程再等待所有進程。不要讓前一個進程先跑完再創(chuàng)建下一個——那樣的話數(shù)據(jù)還沒流到就關閉了而且會復制兩次fork()的環(huán)境效率更低。上面代碼先fork()左命令再fork()右命令兩個子進程都建好之后父進程統(tǒng)一waitpid()。5.4 關注點轉(zhuǎn)移管道實現(xiàn)中容易忽略的“僵尸進程”問題寫管道的時候有個概念你一定會遇到waitpid()的第二個參數(shù)status。我們說父進程“必須”調(diào)用waitpid()等待子進程但如果子進程是管道的一端你可能不知道應該等哪一個先結(jié)束。更隱蔽的問題如果父進程在waitpid(p1)上阻塞而p2已經(jīng)退出p2就變成了僵尸進程——它占著PID和進程表項只有父進程waitpid()收割它系統(tǒng)才會徹底回收。長期積累僵尸進程會耗盡系統(tǒng)進程表。所以更穩(wěn)妥的寫法是waitpid(p1, NULL, 0); waitpid(p2, NULL, 0);兩個都等待確保一個都不漏?;蛘哂脀ait(NULL)交替收割。這個細節(jié)在生產(chǎn)環(huán)境的Shell里是必須處理的但大多數(shù)教學代碼都會略過——我在這兒寫出來是希望你在做項目的時候主動去碰一碰這個問題。6. 交互體驗與常見坑提示符、輸入緩沖、CtrlC、歷史記錄項目做到這里已經(jīng)是個能用的Shell了。接下來這一節(jié)是純“從實戰(zhàn)中踩出來的經(jīng)驗”你在任何教科書上都不太容易湊齊這些細節(jié)但平時敲命令一定會遇到。6.1 提示符的學問交互模式下的fflush和顏色交互式Shell的提示符必須立即顯示。如果你用printf(mysh )標準輸出默認是行緩沖的——只有當遇到換行符或緩沖區(qū)滿才真正寫出去。提示符后面沒有換行所以你不fflush(stdout)的話用戶看到的就是一個干瞪眼的空白終端敲了命令才有反應。這個問題的表現(xiàn)很反直覺按回車之后提示符才出現(xiàn)又跟著你剛敲的命令終端顯示是亂序的。我第一版Shell就載在這里排查了半天還以為是多線程問題結(jié)果就是少了一行fflush。順帶一提給提示符加顏色會讓Shell看起來更友好但要注意非交互模式下不要用顏色。判斷方法很簡單Shell啟動時看isatty(STDIN_FILENO)是否為真。文件輸入或管道輸入時用了顏色反而要命。生產(chǎn)級Shell如Bash就是這么做的。6.2 信號處理為什么按CtrlC會退出你的Shell這是另一個大坑。默認情況下CtrlC會向前臺進程組發(fā)送SIGINT信號默認動作是終止進程。你的Shell如果沒做任何處理用戶在終端按CtrlCShell進程本身就會掛掉。你手寫的Shell必須自己處理SIGINT#include signal.h void handle_sigint(int sig) { printf(\n); fflush(stdout); } int main() { signal(SIGINT, handle_sigint); // ... 主循環(huán) }這樣用戶按CtrlC時Shell只是換個行、重新打印提示符而不是整個進程被殺掉。但注意子進程執(zhí)行期間按CtrlC信號會發(fā)給整個前臺進程組。你的Shell和子進程都在前臺需要決定是Shell處理還是子進程處理。更精細的做法是Shell忽略SIGINT而子進程保留默認行為。所以signal(SIGINT, SIG_IGN)放在 fork 之前的父進程里然后 fork 出來的子進程里再signal(SIGINT, SIG_DFL)恢復默認。這個細節(jié)跟真實Shell的行為一致你在Bash里跑sleep 10按CtrlC能殺掉sleep但Bash還活著。這里面的機制跑通之后你會對“進程組”和“信號傳遞”有更扎實的理解。6.3 歷史記錄用readline庫還是自己擼到了這一節(jié)你已經(jīng)實現(xiàn)了一個可以用于基本命令執(zhí)行、重定向、管道的Shell。如果還想加“上下鍵”翻歷史命令純粹靠自己寫會非常麻煩——因為全終端控制terminal raw mode的細節(jié)比你想的多得多。兩個選擇選擇一用 GNUreadline庫。這是最實際的選擇。它提供了readline()函數(shù)替代getline()并且自帶歷史記錄功能。代碼從char *line readline(mysh ); add_history(line);兩行就完成了。優(yōu)點顯而易見缺點是這個庫要額外鏈接依賴。教學演示項目可以不用靠近生產(chǎn)項目時值得引入。選擇二自己實現(xiàn)簡單的歷史記錄。如果你想鍛煉文件操作能力可以用一個數(shù)組存最近N條命令上下鍵通過終端原始模式讀入按鍵序列。這條路適合練手但“終端raw mode”會花掉你不少時間。我建議先把前述核心功能寫好、跑通歷史記錄用簡單數(shù)組版本即可——不要一上來就擼終端控制。6.4 一個容易被忽略的需求處理空命令和注釋符空行、只含空格的行、以#開頭的行應該被Shell跳過。這在腳本執(zhí)行場景下尤其重要因為腳本文件里經(jīng)常有空行和以#開頭的注釋。第一版可以先忽略但主循環(huán)里面對args[0] NULL的情況要直接continue。還有個細節(jié)把Shell的“退出碼”返回給操作系統(tǒng)。exit命令后你可以echo $?驗證退出碼是否正確。在主循環(huán)里每次執(zhí)行完外部命令從status里提取退出碼WEXITSTATUS(status)存到一個全局變量last_status里。后面實現(xiàn)、||或者$?變量時就靠這個值。7. 一個值得再走一遍的擴展清單這個項目能長成什么樣寫完核心Shell之后你可以繼續(xù)往這幾個方向擴展。這些擴展每一個都能單獨成文而且會逼你解鎖更多Linux機制。1. 通配符展開ls *.txt是怎么變成ls a.txt b.txt的你需要理解Shell的glob展開機制可以自己調(diào)用glob()函數(shù)實現(xiàn)也可以自己寫遞歸匹配。2. 環(huán)境變量賦值前綴VARvalue command這種寫法需要臨時修改子進程的環(huán)境變量。用setenv()在子進程內(nèi)部改但注意父進程環(huán)境不能變。3.$?特殊變量獲取上一條命令的退出碼。這個我們上面提過是通往條件執(zhí)行、||的第一塊磚。4. 作業(yè)控制CtrlZ暫停進程、jobs列出后臺任務、fg恢復前臺運行。這會把高深的前后臺進程組管理引入項目——做完包你理解“作業(yè)控制”是什么。5. 腳本執(zhí)行模式mysh script.sh從文件讀取命令執(zhí)行。這個做起來不難把getline的輸入源換成文件但會觸發(fā)一堆“是否打印提示符”等邊界判斷——跟真實Shell一致非交互模式不打印提示符。6. 引號處理完整支持單引號和雙引號。單引號內(nèi)一切字符按字面意義處理雙引號內(nèi)做變量替換。這需要把簡單的strsep解析器升級成帶狀態(tài)機的解析器。做完你就會明白為什么Shell的解析器一直是“復雜主題”。每做完一個擴展建議你做一個小對比用自己的Shell跑ls -l /tmp再去Bash里跑同樣的命令看看行為差異有多大。你會感受到從“模擬”到“理解”之間的距離。最后說一點個人體會。磨這個項目的時候我最深的感觸不是“哦原來Shell是這么工作的”而是“需要一個好用的測試工具”——自己寫Shell意味著你手里的每個命令都是被自己實現(xiàn)的代碼執(zhí)行的。當你發(fā)現(xiàn)自己寫的Shell居然能正確跑grep -r hello /usr/include | wc -l時那種“操作系統(tǒng)的拼圖在自己手里一塊塊拼上”的感覺特別踏實。而且這是一個適合長期維護的小項目。它不會太大但每次往里加一個功能、處理一個bug都能讓你對Linux的理解再深一圈。過三個月拿出來看看你會發(fā)現(xiàn)自己寫的代碼其實菜得不行——那恰恰說明你成長了。建議從今天開始動手先把3.3小節(jié)的parse_command()跑起來剩下的自然就有動力磨下去了。
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
极品另类| 亚洲超碰在线| 91avse| www天堂99| 丁香五月天在线| 狠狠草网| 热热色色五月天婷婷| 五月天婷婷丁香| 久久激情五月| 丁香五月天五码婷婷| 日本九九九九九九| 天天日天天插| WWW久久久| 丁香激情合作五月| 操操操www.com| 97碰精品| 99精品视频在线观看| 久热只有这里有精品| 97夫妻超碰| 天天草天天爽| 亚洲精品色色色| av色婷婷| av在线播放网址| 九九热123| 婷婷99狠狠躁天天| 丁香五月综合| 色婷婷操逼网| 亚洲九九99精品视频在线播放| 五月激情综合网| 五月天天天开心激情网| 婷婷在线观看五月天在线视频| 婷婷狠狠香蕉综合| 成人美女网| 色五月激情| 五月婷婷色播网| 玖玖99免费视频| 这里只有精品96| 少妇人妻人伦A片| 色综合xx| 婷婷五月天Av| 久久综合婷婷| 丁香婷婷五月激情| 色爱综合网| 9l久久久视频| 欧美激情-区二区三区| 狠狠狠狠狠操| 久久五月天激情婷婷| 激情五月天啪啪| 色色色香蕉五月婷| 9色资源在线| 婷婷五月天小说| www九九热| 深爱婷婷丁香五月激情| 国产成人99久久亚洲综合精品| 欧美色播综合在线观看| 婷婷五月天激情五月天网站| 激情五月天婷婷久久久久久久久久久| 大香蕉五月| 欧美日韩婷婷五月天| 天天爽天天| 思思久久精品| 亚洲综合视频网| 丁香五月欧美| 可以直接看的AV网站| 天堂在线婷婷| 亚洲综合网在线| 99re6久热只有精品6在线直播| 成人一级片| 99re思思久久| 亚洲综合1024| 99免费热视频在线| 婷婷色情 | AA片在线观看视频在线播放| www.cao.com久久| 精品九九九久| 玖玖婷婷综合| 五月天成人伊人| 婷婷五月天伦理| 色5月婷婷| 丁香婷婷性爱| 开心五月综合激情综合五月| 色色色综合网| 4399成人黄A片| 激情综合婷婷五月| 欧美成人精品老美女噜噜噜| www.99婷婷| 99热精品在线播放| 超碰在线中文字幕| 99视频在线观看地址| 在线视频区| 欧美A片在线视频免费观看| 色九九中文字幕| 亚洲国产精品VA在线看黑人| 色综合丁香婷婷| 丁香六月婷婷一区| 五月天色官网| 色色色色色色色色色色色色色97| 免费黄色视频网址| 婷婷丁香九色| 久久AV无码精品人妻系列试探| 性按摩玩人妻HD中文字幕| 婷婷激情综合网| 亚洲国产va| 激情五月天婷婷五月天| 亚洲va综合va国产va中文| 精品皮股午夜AV| WWW,五月| 超碰免费在线| 亚洲AV免费在线| www.五月天| 久久99久久99精品,久国产,久久精品免费,99久在线,久久久久国产精品免费网站,9 | 中文字幕 中文字幕明步| 激情五月天开心| 婷婷激情综合网| 综合激情sV| 综激情网| 俺也去在线视频| 啪啪啪五月天| 99综合| 丁香五月社区| 久久精品99久久久久久| 婷婷五月丁综合| 五月婷婷激情视频| 做爰丰满少妇1313| 色婷婷手机在线| 互月天综合| 五月丁香啪综合| 超pen个人视频97| 久久丁香网| AV在线免费播放| 《》【无码】想被搞到爽AV应募而来的超M素人 西纯子 10musume-011723-01 | 91精品国产99久久久久久天美| 91在线看片| 综合久久8| 99九九视频| 九九成人精品免费视频| www.婷婷六月天| 超碰av在线| 国产在线网| 99热亚洲精品| 色五月偷偷| 丁香婷婷AV| 六月激情久久婷婷| 激情五月天婷婷| 色婷婷成人做爰A片免费看网站 | 婷婷五月丁香影院| 午夜亚洲国产精品av一区二区| 久综合4| 97碰在线视频| 激情AV| 99玖玖免费视频| 九九99久久| 九九色色色| 婷婷丁香五月高清| 综合亚洲AV| 欧美天天爽| 丁香五月激情婷婷| 99啪啪视频| 天天操加勒比| 亚洲综合在线视频| 亚洲无码99| 国产激情视频在线观看| 超碰99在线观看| 1024操逼| 思思久久99| 五月丁香亭亭操逼| 五月婷色色| 欧美三级韩国三级日本三斤| 国产高清精品色| 91Chinese在线| 亚洲AV成人片无码网站| 婷婷五月天伊人| 国产婷婷综合在线免费视频| 亚洲色色爱| 五月婷婷久久综合| 超碰狠狠色| 热99.com婷婷| 91精品丝袜久久久久久| 日日噜狠狠色综| www.色婷婷| 九九这里只有精品在线视频| 在线观看免费人成视频无码| 国内婷婷丁香社区在线播放| 狠狠色色色| 五月色无码| 亚洲亚洲人成综合网络| 天天谢天天操| 五月婷啪啪| 五月色网| 五月婷婷欲色| 久草五月婷婷| 精品人妻伦九区久久AAA片| 婷婷 激情 五月| 丁香网五月天| www.五月天婷婷| 天天天天干| 婷婷五月天在线观看av| 五月 婷 久| 色婷婷69| 五月丁香五月婷婷在线观看| 丁香五月色色色色| 色爱99| www.激情五月| 久婷久婷| 66精品成人免费网站在线观看| 五月丁香综合中文| 亚洲中文字幕AV在线| 五月天激情啪啪| 色情·com| 激情丁香五月天图片| 思思精品视频| 噜噜色五月| 天天色五月| 五月丁香激情综合啪啪| 超碰妻人人| 久久综合热17c| 国产综合81p| 中文字幕丰满孑伦无码专区| 激情综合五| 美女五月天| 夜夜骑日日操| 亚洲婷婷五月天在线激情综合网| 丁香婷婷色情| 婷婷激情四射五月天| 五月丁香亭亭| 狠狠狠狠狠狠狠狠| www.久久久久| 五月婷婷熟女| 婷婷欧美综合| 99re视频在线播放| 九九婷婷综合| 亚洲综合五月天婷婷丁香| 亚洲射激情| 182TV大香蕉| 色婷婷五月丁香色| 日韩三级高清无码| 黄网在线观看免费| 九月婷婷激情| 五月天婷婷AV| 婷婷激情综合| 深爱五月婷婷| 日韩精品一区二区亚洲AV观看| 亚洲色a| 丁香香五月激情免费视频| 91视频一起草| 日韩黄黄| 无码色色色色色| 九月综合| 久久综合五月天| 五月天婷婷涩涩| 丁香久久在线| 九九综合五月欧美| 久久99看免费| 99热国产精品| 日本激情ⅩXX免费视频| 丁香六月色情| 精品99在线观看| 婷婷色影音天| 欧美三级视频下载| 在线观看亚洲视频影院| 五月色综合网欧美网| 久久久五月五丁香| 丁香丁婷五月激情| 狠狠干伊人| 五月婷六月丁香| 开心激情站婷婷五月天| 99热精品无码| 涩五月婷婷| 在线观看中文字幕| 97超碰,人人舔,人人操,人人摸 | 亚洲色婷婷色| 婷婷之六月丁香| 色五月六月婷婷| 婷婷五月天成人综合网| 91九色精品女同系列| 亚洲啪啪啪啪| 青柠影视免费高清电视剧| 51精品国自产在线| 五月丁香花视频| 精品人人操| 天天爽夜夜爽夜夜爽精| 日本五月天一页| 天天肏高清在线| 伊人干综合| 99色| 丁香婷婷超碰 | 人人摸人人摸| 五月婷婷色播| 9在线9在线婷婷在线国产| 91操在线观看| 五月婷婷久久综合| 婷婷五月在线观看| http:色情日本com| 久久激情五月婷婷| 五月天婷婷黄色| 99综合视频| 久久婷婷视频| 久久视频婷婷| 人妻操在线看| 开心五月网| 丁香六月欧美| 日日天天干| 欧美六月| 中文字幕精品推荐免费在线观| 五月天停停日日| 久久丝丝热| 天天操夜夜爽| www久久99| 婷婷五月丁香人妻无码高清| 色婷婷成人在线| 婷婷综合五月天| 国产亚洲在线观看| 久久久久亚洲AV成人无码电影| 天天操九九插| 综合激情站| 丁香五月激情综合久久| 激情影院免费视频婷婷五月天| 99热国产免费| 91亚洲视频| 婷婷综合激情| 97丁香五月| 国产午夜成人免费看片无遮挡| 婷婷九月狠狠色| 五月综合六月丁| 黄网在线观看免费| 1024你懂的欧美曰韩| 久久五月丁香婷婷| 婷婷五月丁香综合| 91凹凸在线| 天天夜天天色天天| 九九九九操逼| 欧美色播综合在线观看| 人人摸人人摸| 日本久久高清| 一区视频网站| 九热视频在线精品15| 天天搞天天色综合| 99色嘟嘟精品网站| 国内精品玖玖| 成人性生活免费观看。| 丁香五月六月激情| 色五月丁香com| 另类色视频| 狠狠人妻色综合| 97sese婷婷| 热的无码综合视频| 丁香五月天天久久综合小说| 思思w99| 99免费在线视频| 九九热黄色| 99热精品在线观看| 欧美日本国产欧美日本韩国99| 婷婷五月天黄色小说| 婷婷伊人久久无码色五月| 热的国产,热的综合,热的有码| www久| 国产91视频| 伊人久久大香网| 五月婷六月| 亚洲色五月天是什么| 婷婷99视频精品| 久久九⑨| 久久婷婷视频| 99热在线精品观看| 五月婷婷av| 久热大香蕉| 日本片日本片祼观看网站在线看中文版网页在线看 | www.婷婷五月天| 婷婷精品在线| AA丁香综合激情| 丁香六月婷婷综合激情欧美| 天天综合在线网| 啪啪啪大香蕉| 国外亚洲成AV人片在线观看| 开心五月天激情| 丁香五月瑟瑟| 六月婷婷色色色| 91九色中文字幕女在线观看| av人人干| WWW.99热| 婷婷免费无马| .精品久久久麻豆国产精品| oVV4WIB3vFi8D| 五月婷婷丁香91| 深爱激情婷| 色吊丝永久访问网址| 日韩啪啪视频| 天天射影视综合网| 九九av在线| 综合色色网| 3pAV| 无码动漫AV| 色综合中文| 婷婷久久午夜网| 国产熟妇乱子伦hd| 182TV大香蕉| 欧美性爱五月天| 亚洲亚洲人成综合网络| www.99热| 丁香婷婷六月激情| 欧美色九| 激情五月天久久| 免费看欧美成人A片无码| 99ri在线观看视频| 99青青草99| 99久久99久久| 米奇影视资源婷婷狠狠色激情欧美五月丁香 | 久热这里只有精品在线| www超碰| 久久精品一区二区三区四区| 无码人妻电影| 激情小说五月欧美亚洲丁香| 国产99热在线看| 91久久18| 思思久久99热只有频精品66| 亚洲精品电影| 久久国产色| 成人色站,在线视频,看片-SS1AV| 五月天激情啪啪| 成人无码髙潮喷水A片| 这里只有精品视频| 99er视频在线| 秋霞学生妹一二级| 欧美在线干| 九九综合88| 色色婷婷五月| 激情婷婷五月天| 色爱亚洲| 狠狠插狠狠| 男人的天堂999| 综合网狠狠| 久久色大香蕉| 男女啪啪做爰高潮无遮挡 | 97碰在线视频| 思思热在线视频精品| 婷婷五月AA五月在线| 天天搞天天色综合| 日本黄色在线观看| 亚洲六月色| 狠狠艹狠狠艹| 五月丁香日本一抹本| 五月丁香婷婷婷激情爱爱| 激情婷婷丁香五月| 99热66| 久久婷婷伊人| 五月天婷婷视频| 亚洲无码成人| 九九久久五月天| 2017人人操| 五月丁香六月婷婷国产视频| 99国产这里只有精品| 婷婷六月久久| 亚洲 六月 综合| 69午夜成人影片| 夜夜爽天天| 无码se| 国产综合视频婷婷| a在线观看| 97色97干| 综合网色| 久久这里只有精品视频15| 成人无码精品1区2区3区免费看| 人妻啪啪啪| 99在线精品免费视频| 九月婷婷久久久| 五月婷婷av| 91综合国免费久入| 桃色五月天| 久久六月天| 激情欧美五月丁香| 欧美性生交XXXXX无码小说| av大香蕉| 99久久婷婷国产综合精品电影| 97干干干丁香| 婷婷五月激情综合啪啪| 五月丁香六月成人| 婷婷五月天成人五月天| 婷婷丁香午夜综合影视| 久8色色| 桔色成人在线| 久久久久亚洲AV成人无码电影| 亚洲综合在线播放| 婷婷丁香五月亚洲17cao| 天天拍天天操| 热99视频精品在线| 99亚洲精美视频在线观看| 九九精品综合| 亚洲色婷婷婷婷人人爽| 日操夜撸| 婷婷五月丁香久久| 丁香五月影| 色五月婷婷影视| 9久热在线视频精品| 伊人在线视频| 91丁香婷婷综合资源| 成人av中文字幕| 综合激情五月丁香9999久久精| 夜夜操少妇| 涩涩涩五月天| 婷婷九月色| 婷婷综合玖玖五月| 淫视馆aV二区一区| 色欲五月婷婷| 色婷婷狠狠| 天天干天天日蜜臀av| 99ri在线播放| 色婷婷五月天小说网| 狠狠色噜噜狠狠| 五月丁香亭亭| 《久久综合九色综合97婷婷| 五月天色狠狠| 97碰成超视频免费视频| 久久五月天婷婷| 超碰人人在线| 久久色午夜在线导航| 97caop| 三级三久久线久久99久目本WW| site:wpjngj.com| 在线成人网站| 婷婷视频网| 狠狠爱婷婷爱| 黄色精品五月婷婷| 91碰超| 亚洲 欧洲 国产 伦综合| 丁香五月婷中字在线| 成人精品视频99在线观看免费 | 亚洲黄网在线| 五月激情婷婷偷拍| 五月丁香六月停停停| 伊人久久大香线蕉精品| 99热有精品在线观看| 香蕉久操| 91精品久| 婷婷丁香精品视频在线观看| 996er在线观看| 国产脫衣舞一区二区三区| 久久婷婷五月激情综合| 99热插| 五月丁香综合影院| 99热综合色图| 丁香九月久久| 婷婷五月蜜桃成人桃色丁香| 国产探花一片区| 97操碰在线97| 天天操五月天| 丁香五月婷婷超碰在线| 天天五月丁香五月| 五月婷婷六月激情在线| 中文字幕性爱丰满| 五月婷婷亚洲| 婷婷五月AV| 天天舔日日肏夜夜爽| 色色色地址| 1234操逼网| 婷婷中文字暮| 色五月美女| 色婷激情网| 97久久超碰| 亚洲成人综合在线| 久操操| av网址在线| 影音先锋91| 丁香五月AV| 五月天婷婷激情| 激情国产综合| 精品99在线| 任你操精品免费| 噜噜在线| 午夜色婷婷| 五月婷婷啪| 99久热在线精品| 777久久精品| 91色久| 色之综合网| 日日干夜夜干| 丁香成人综合| 以及AA大片看看| 丁香五月av在线| 日本三级日本黄色| 五月天色婷婷综合| 婷婷五月天堂| 狼人久草| 五月天堂在线| 亚洲AV无码影院| 久久hd| 婷婷欧美综合| 青草视频在线观看视频| 26uuu另类亚洲欧美日本一| 999精品久久久久久久| 婷婷九月丁香| 如何安全看伊人婷婷| 婷婷五月天在线观看| 婷婷五月天手机版视频| 久久久久五月丁香| 久久婷婷五月综合| 亚洲看av的网站| 久热天堂| 狠狠穞A片一區二區三區| 婷婷丁香五月天色色| 超碰在线免费9| AV伊人青草丁香六月| 久热一区| 大香蕉久久久| 夜夜爽日日躁| 先锋资源91| 婷婷午夜| 久色视频| 婷婷五月天激情偷拍| 亚洲精级| 97色色综合| 亭亭社区五月天| wWW九九在线播放| 六月婷婷色综合| 99re鈥哸鈥唙| 婷婷六月综合在线| 97极品在线| 国产肥白大熟妇BBBB视频| AV人人操| 色五月婷婷在线视频| 色色九区| 日本女色人人| 五月婷婷片| 丁香五月综合在线观看| www久久99com| 中文AV在线观看| 丁香五月开心婷婷| 综合亚洲色色| enecarbon-materials.comWu染请涟系Bao护@wip1688 | 99热这里都是精品| 日韩在线9| 中文不卡一二区| 亚洲综合激情五月久久| 婷婷色偷拍| 9热网站| 婷婷导航| 婷婷五月天AV在线| 丁香成人视频| 久久久精久人妻| 99re这里只有精品99| 欧美久久久久久久久中文字幕| 丁香六月婷| 91欧美日韩综合| 这里只有久久精99| 久久婷婷五月综合啪| 亚洲第一色色色| 婷婷激情性爱| 婷婷激情人妻| 五月婷婷六月丁香首页| 五月婷婷激情在线| 九九婷婷五月天| 超碰av在线| 在线婷婷| 六月丁香射婷婷欧美色图片| 思思99热热热99| www.五月婷婷久久.com| 国产老熟妇亲子乱对白| 天堂综合久| 大香伊人婷婷影院| 五月丁香激情综合网官网| 激情内射人妻1区2区3区| 99这里有精品| 日日操夜夜爽| 久久久97| 99精彩视频| 99久久婷婷国产综合精品草原| 色人久久| 五月丁香六月婷婷啪啪| 能看的AV| 天天爽天天| 日本99久久| 九九色热| 丰满少妇猛烈A片免费看观看 | 超碰在线超碰| 人人操插| 婷婷免费精品视频| 五月六月丁香婷婷在线观看| 天天色伊人| 26uuuu精品一区二区| 另类丁香五月天区图| 91色综合网站在线| 成人AV片播放| 久久丁香九| 久操干| 五月婷婷激情性爱| 五月天日日操夜夜操 | 丁香九月婷婷色| 午夜电影网VA内射| 天天爱天天吃狠天天透| 免费观看亚洲AV片| 欧洲色| 激情九月婷婷九月| 91天堂网综合| 婷婷色色网| 99热国产这里只有| 蜜桃五月天| WWW.桔色成人.COM| 色五月婷婷五月| 少妇性按摩无码中文A片| WWW.五月com| 狠狠爱婷婷丁香| 天天情天天狠天天透| 久久av电影| 狠狠高潮精品亚洲1| AAA久久| 99精品视频在线观看| 青青操日本摸摸看看| 啪啪 综合网| 天堂爱爱| 五月婷婷六月丁香在线| 国产高清RV综合aVa| 五月丁香偷拍| 久久香蕉影院| 黄色99热| 色五月天天| 丁香五月欧美午夜视频| 99热色精品| 丁香婷婷婷婷十二月在线观看视频| 五月丁香操婷逼| 丁香婷婷六月天| 99爱视频| 中文字幕在线aⅴ免费观看| 天天综合 99久久婷婷| 亚洲mm色| 99re久久| 久久免费试看120秒| 天天情天天狠天天透| 天天日夜夜爽。| 97碰免费视频在线| 5Www色5夜| 色狠狠五月天| 中文av网| 艹B高清无码| 久久伊人大香蕉| 丁香五月中文字幕久色| 丁香婷婷大香蕉| 久久 无毛。| www,五月丁,com| 99综合视频| 91无码高清| 国产AV熟妇人震精品一品二区| 欧美日本国产欧美日本韩国99| 五月色婷婷激情| 亚洲情欲| 91狠狠色色丁香婷婷综合久久| 五月丁香五月天现场视频| 少妇激情五月天| 婷婷五月天大香蕉| 夜夜操,天天撸| 99国产精品久久久久久久久久久| 7777激情基地| 日本WWW九九九| 婷婷丁香精品视频在线观看| 日韩av干| 青草视频在线观看视频| 国产97在线日韩亚洲女人被黑人巨大| 丁香五月婷婷欧美激情-中文天堂最新版在线观看| 婷婷六月丁香久| 99热这里只有精品2| 影音先锋天天日| 久久亚洲婷婷| 教师性爱毛片| 五月丁香 啪啪啪| 无码激情AAAAA片-区区| 欧美婷婷六月丁香综合色连续高潮抽搐| 97碰超级人人看| 六月丁香色色色| 五月天六月色| 婷婷玖玖丁香| 成年人丁香五月| 狠狠色丁香久久综合婷婷亚洲成人福利 | 大香蕉五月天婷婷| 色婷久九| 另类A片| 人人操97| 狠狠干综合| 777影视理论片大全在线观看| 亭亭五月丁香综合欧美| 丁香色婷婷| 丁香五月婷婷深爱综合激情 | 六月婷欧美| 欧美在线视频免费播放| 超碰三级片| 国产精品日日躁夜夜躁| 欧美色宗和激情| 婷婷天堂站| 玖玖视频福利| 人人添人人| 99婷五月| 激情五月婷婷综合| 超碰91人人操| 99这里只有精| 天天综合.com| 狠狠爱丁香婷| 亚洲色色色| 五月婷婷丁香| 免费无码毛片一区二区A片| 99热这里只有精品69| 影音先锋男人站,影音先锋男人色资源网,影音先锋AV最新资源站,影音先锋AV资源 | 99se丁香| 激情综合网五月丁香| 综合久久婷婷| 99热国产国产| 在线中文字幕免费视频| 九九色热| 五月开心婷婷极品激情| 熟女少妇内射日韩亚洲| 精品人妻久久久久| 色久九| 一本大道熟女人妻中文字幕在线| 五月天俺去也| 外国碰视频网站97| 婷色五月天| 丁香五月婷婷俺也要去| 久久激情天堂| 婷婷五月天福利| 天天色官网| 中文字幕97超级碰| 99热这里有精品| 丁香五月婷婷色情综合| 九月色婷婷| 99热传媒| 丁香婷婷基地| 99热只有这里才是精品| 色碰干| 亚洲V国产V欧美V久久久久久| 情久久综合五月天| 深爱婷婷基地| 天堂在线婷婷| 色九区| 这里只有精品视频在线| 这里只有精9| 欧美日韩国产一区二区| 五月天综合在线| 天天影院色| 深爱激情四射| 久久久久婷婷| 婷婷五月天天爽| 色婷婷丁香五月在线| 九九视屏| 大香蕉五月婷婷丁香| 97色在线视频| 思思精品热在线| 久久久久久久综合狠狠综合| 久久五月天免费网站| 五月丁香综合激情| 九九视屏| 婷婷五月天天aV| 色婷婷丁香网| 久综合九| 婷婷色色宗合网| 欧美大肥婆大肥BBBBB| 超碰97免费在线| 超碰av在线| 亚洲综合另类| 26uuu欧美激情另类| 婷婷亚洲五| 操操自拍| 综合久久伊人| 色情终和网| 激情丁香婷婷| 天天射美女| 五月亭亭直播| 久色国产| 婷婷五月天,影院| 伊人影音无码一区二区三区| 五月天激情网址| 超碰啪啪网| 综合久久五| 日本精品久久久久中文字幕| 亚洲色欲欧美一区二区三区| 91九色网| 丁香六月久久| 九九十99视频| 五月丁香九九| 一区二区三区XXXXXX| 开心婷婷五月综合| 秋霞少妇AV网站| 99精品国产在热久久| 日本色婷婷| 亚洲激情网| 91蜜桃婷婷狠狠久久综合9色| 另类小说色婷婷| 欧洲亚洲精品| 久久天天| 激情五月天网站| 色激情五月天| 婷婷综合一二三| 色色色婷婷| www.五月天婷婷| 91激情五月开心| 久久99综合网| 九九综合伊人| 99九九精品| 人人干av| 五月丁香啪啪啪| 99精品视频在线观看| 国精产品一区一区三区免费视频| 熟妇人妻中文字幕无码老熟妇| 激情丁香五月婷婷| 成 人片 黄 色 大 片| 国产日韩精品SUV| 欧美成人在线观看| 99热色综合| 热99久| www.91在线观看| 九九亚洲视频| 色婷婷视频| 蜜臀av在线成人电影| 99碰| 精品久久99码| 久久99激情| 天天干天天色天天干| 色色综合色| 色综合丁香婷婷| 五月天丁香网| 97精品人人A片免费看| 婷婷婷婷午夜| 任你日热视频| 五月婷婷性爱| 丁香婷婷人妻综合网| 日本熟女内射| 亚洲色夜| 色色色综合| 免费播放AV| 九九99免费理论| 婷婷瑟五月天久久综合| 五月婷天天搞视频| 婷婷久热| 色狠狠色综合久久久绯色aⅴ影视| 91seAV| 美日韩成人| 五月婷婷六月激情网| 99在线精品视频| 天天操天天插| 久久密臀婷婷| 九九色99| 婷婷五月天电影在线| 播五月开心婷婷欧美综合| 97操操| 成人一区在线观看| 亚洲婷婷丁香五月在线| 亚洲欧美999| 久久婷婷五月| 中文字幕欧美精品久久| 99热大全在线观看| 深爱激情丁香五月| 开心五月激情网| 丁香六月激情国产| 激情五月深爱五月| 99re66热这里只有精品| 丁香婷婷视频一区二区| 丁香五月成人社区| 国产女人十八水真多1| 丁香五月六月久久综合 | 99爱视频| 在线观看免费人成视频无码| 日韩欧美成人片| 天天干天天干天天干天天干天天干天天 | 91精品综合久久久久久五月丁香 | 久久久久婷婷五月热综合| 五月天婷婷在线播放| 97人人草| 久久五月网| 99热99热在线| 国产乱妇乱子在线播视频播放网站| 五月丁香色婷基地综合久久| 婷婷五月天激情综合深爱| 色色五月丁香婷婷| 91精品国产色猫| 五月人妻婷婷| 色九九综合| 殴美日韩成人| 天天综合天综合| 思思久久99热只有频精品66| 欧美人人操| 久久人人妻| 91女人18毛片水多国产| 丁香五月另类小说在线阅读| 久热九九| 999久久久国产精品| 天天五月情| 激情五月婷婷丁香| 韩国中文字幕91| 天天舔夜夜操www com| av网址在线| 五月天婷婷情色| 五月色综合网| 色婷婷91激情小说| 久久99这里只有精品视频 | 婷婷综合色播网| 99原创自拍视频在线观看| 亚洲无码成人网| 亚洲美女高潮久久久久久69| 婷婷色在线视频| 色色色99| 免费AV在线网址| 99热这里只有精品2| 亚洲黄网在线| 婷婷五月六月激情| 久久久aaa| 色爱终和网| 丁香五月婷婷av影院| 国产99视频永久免费| AA片在线观看视频在线播放| 国产婷婷综合| 天堂无码人妻精品AV一区| 4399在线观看免费高清电视剧| www.婷婷五月| 欧洲99视频在线| 丁香五月婷婷网| 、激情六月天| 777精品久无码人妻蜜桃| 色99视| 亚洲亚洲人成综合网络| 69激情小说| 激情五月天婷婷播播久久综合91| 色五月综合婷婷| 色婷婷91激情小说| AV性爱在线| 九九99热| 一级黄色影片| 天天日夜夜高潮| 国产乱妇无乱码大黄AA片| 婷婷五六日| 伊大人久久| 美女天天爽| 天天弄天天操| 婷婷五月天影视| www.wuyuetian啪啪| 五月天激情AV| 91疯狂操操操操| 成人电影一区| 丁香六月av| 日本波多野结衣视频| 九九激情| 色999亚洲人成色| 国产真人做爰视频免费| 久久人妻高清中文| 91pornav在线| 99精品在这里| 天天日夜夜操五月| 人人操大| 久久香蕉网| 天天摸日日舔狠狠添婷婷婷| 丁香五月婷婷婷桃花影院| 久久婷婷网| 丁香婷婷激情五月色| 丁香五月婷婷五月基地| 综合久久高清| 欧美精品久久久久久视频观看| 91免费啪视频| 99热综合网| 成人色情五月天婷婷丁香| 色色五月丁香婷婷综合| 99热这里只有精品99| 五月丁香花开综合网| 超碰免费大香蕉| 麻豆AV一区二区三区| 九九精品免费| 天天做天天双| 日本在线99| 欧亚成人A片一区二区| 久热免费视频| 五月色情网| 久99热在线观看| 国产毛片精品一区二区色欲黄A片| 日韩AAAAAAAAAAA片| 婷婷五月激情六月丁香| 免费AV在线网址| 亚洲日韩一页精品发布| 六月婷婷激情| 天天操夜夜夜拍拍拍| 97se视频在线| 成人综合网站| 激情五月最新网址| 日韩高清久久| 色色婷婷丁香| 中文字幕黄色电影网址| 婷婷五月综激情| 99色在线观看免费| 玖玖精品资源| 婷婷五月丁香五月综合网| 97在线刺激| 99久在线精品99re8热| 狠狠干五月| 激情 婷婷| 中文字幕成人| 五月天激情中文字幕| 涩涩涩五月天| 人妻中文在线| 91人久| 伊人久久综合| 色噜噜狠狠色综合AV兰草影视| 2023天天日夜夜爽| 五月婷婷丁香婷婷| www.99色| 久草丁香婷婷1024| 亚洲婷婷久久综合| 99在线观看免费精品视频| 丁香五月欧美激情| 婷婷色丁香五月| 熟妇人妻中文字幕无码老熟妇| 婷婷激情97| 五月综合久久| 九九热视频思思| 久热黄色| 香蕉久操| 亚欧州精品视频| 操逼福利视频| 色综合久久88色综合天天看| 91操人| caopeng97人人| 久久99热这里| 日日噜噜夜夜狠狠久久丁香五月| 日本狠狠干| 综合网网欲色| 色日本丁香婷婷| 九九在线精品| 久久精品99国产精品日本| 色香久久| 很很操很很操| 五月天丁香成人| 精品国产AV色一区二区深夜久久| 亚洲综合另类| A A色色| 99热国产| 亚洲综合欧美色丁香婷婷888月图片| 亚洲色区17| www.狠狠| 中文在线成人| 狠狠色丁香婷婷基地| 久婷婷婷| 国内熟女黄色系列| 婷婷日在线观看| 九九无码| 色五月天婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷 | 农村熟妇高潮精品A片| 丁香网站| 色日本颜射| 亚洲xx在线| 亚洲免费成人电影AV| 综久久久| 久一网站| 亚洲综合视频在线| 99综合免费视频| 欧美成人无码一区二区三区| 亚洲久久视频| 天天射天天射一道本日本社区| 五月天电影网| 成人中文网| 狼人久草| 91九色网| 激情五月天综合网| 六月婷婷综合久久| 开心激情播播五月天| 中文字幕无码人妻少妇免费视频| 99在线观看视频| 强伦轩人妻一区二区电影| 久久久一级AAA| 开心五月激情| 狼人久草| 久大香蕉| 五月天激情综合在线| 欧美啪啪9| 另类丁香综合| 天天色天天色天天色天天色天天色| 国产亚洲99久久精品| 久久九九综合| 婷婷久久五月丁香| 日本99色| 婷婷五月天美女21p| 精品婷婷丁香五| 艾小青av| 人妻丰满精品一区二区A片| 综合狠狠伊人| 色婷婷电影| 日韩成人av在线| 欧美视频五区| 超碰无码318604| 66成人网| 成人资源在线| 成人精品亚洲性爱| 欧美日韩国产成人在线| 丁香五月天成人| 久久婷婷五月天丁香| 91啪级电影| 性色做爰片在线观看WW| 婷婷九月激情| 色色亚洲| 天天在线久久综合| 少妇性BBB搡BBB爽爽爽视頻| 欧美综合婷婷欧美综| 久久小说| 玖玖福利视频资源| 丁香六月丁香婷婷激情| 五月花亭亭| 99碰碰。| 五月丁香淫淫婷婷婷| 91日综合欧美| 天天在线XXX| 性天堂久久| 日韩一级片| 色99热| 五月天激情小说网| 九九精品视频免费在线| 日本三级大片| 黄色99视频| 色综合色色| 另类图片五月天婷婷| 日本精品人妻无码77777| 五月婷婷激情色情网| 狠狠爱成人综合网| 色噜噜狠狠插综合| 色五月97| 五月婷网| 色激情综合狠狠婷婷| 乱精品一区字幕二区| 亚洲 五月 婷婷 成人| 精品一区二区三区三区| 在线观看欧美| 婷婷色网| 亚洲国产精品VA在线看黑人 | 亚洲色就是色色色| 激情五月天无人视频在线| 日韩久综合| 99视频内射三四| www.日日日.com| 婷婷五月丁香国产| 久久99热这里只频精品6学生| 五月丁香福利| 第九色区av天堂| 人人视频色| AV色婷婷| 五月激情在线| 天天 日综合| 99色在线观看视频| 操婷婷久久| 俺也去在线视频 | 五月天激情网站| 五月份婷婷| 99re8这里只有精品99re8热视频| 亚洲婷婷丁香| www久久艹| 久久人人九| 七七色色综合| 啪啪夜久久| 欧洲色色| 日亚二欧美| 五月天婷婷久久| 视频久久9| 五月婷婷五月色| 亚洲成人av在线播放| 99精品在线观看视频| 六月婷婷激情图片| 国产97色在线| 色久九| 欧美日综合| 久久人妻久久| 激情综合五月激情17| 三级三久久线久久99久目本WW| 天天干,天天舔| 天天日天天操心| caopeng超碰| 在线18av | 五月激情婷婷女| 天啪色|