四虎国产精品永久地址998_chinesexxx少妇露脸_日本丁香久久综合国产精品_一区二区久久久久_四虎av影视_久久久久国产一区二区三区不卡

中培偉業(yè)IT資訊頻道
您現(xiàn)在的位置:首頁(yè) > IT資訊 > IT運(yùn)維 > 如何構(gòu)建一個(gè)Linux Shell(四)

如何構(gòu)建一個(gè)Linux Shell(四)

2020-07-24 17:41:30 | 來(lái)源:中培企業(yè)IT培訓(xùn)網(wǎng)

這是有關(guān)如何構(gòu)建Linux Shell的教程的第四部分。在這一部分中,我們將向我們的外殼添加符號(hào)表。的符號(hào)表是用于由數(shù)據(jù)結(jié)構(gòu)的編譯器和解釋器來(lái)存儲(chǔ)變量如表中的條目。每個(gè)條目都包含一個(gè)鍵(變量的名稱(chēng))和一個(gè)關(guān)聯(lián)的值(變量的值)。鍵通常是唯一的,也就是說(shuō),我們不能有兩個(gè)共享相同鍵的條目(即,不能有兩個(gè)共享相同變量名的變量)。

通常,Linux Shell在啟動(dòng)時(shí)會(huì)填充其符號(hào)表。填充符號(hào)表后,編譯器或解釋器可以輕松地在表中搜索變量以檢索該變量的值。我們還可以執(zhí)行類(lèi)型檢查,執(zhí)行作用域規(guī)則(例如,使變量?jī)H對(duì)聲明其的函數(shù)可見(jiàn)),并將shell變量導(dǎo)出到外部命令。

為了填充符號(hào)表,外殼程序讀取環(huán)境變量列表,該環(huán)境變量列表從其父進(jìn)程(通常是登錄用戶(hù)的進(jìn)程或登錄進(jìn)程的子進(jìn)程)傳遞到外殼程序。Shell將每個(gè)變量(及其值)添加到符號(hào)表中。然后,我們可以使用適當(dāng)?shù)膬?nèi)置實(shí)用程序隨意編輯,刪除或?qū)С鰏hell變量(我們將在本系列的稍后部分中討論)。

  為什么我們需要符號(hào)表?

簡(jiǎn)而言之,符號(hào)表使我們能夠定義外殼變量,修改它們的值,在執(zhí)行變量擴(kuò)展時(shí)使用不同外殼變量的值以及將變量導(dǎo)出到外部命令。在本系列后面的內(nèi)容中,當(dāng)我們討論位置和特殊外殼參數(shù)時(shí),符號(hào)表也將變得很方便。

每當(dāng)您要求外殼程序回顯,導(dǎo)出或未設(shè)置外殼程序變量的值時(shí),您實(shí)際上就是在要求外殼程序訪問(wèn)和/或修改其符號(hào)表。所有外殼程序都有某種符號(hào)表實(shí)現(xiàn),盡管某些外殼程序可能具有不同的名稱(chēng)。

例如,假設(shè)您調(diào)用了以下命令:

echo $PATH

哪個(gè)應(yīng)該給你類(lèi)似的輸出:

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

您可能知道 echo 該命令與您在屏幕上看到的輸出無(wú)關(guān),除了以下事實(shí): echo打印出路徑。它的外殼究竟是誰(shuí)明白$PATH 代表外殼變量名稱(chēng)。

也是貝殼代替了單詞$PATH 帶有實(shí)際路徑值,然后將其傳遞給 echo。的echo 命令只是回顯了外殼程序傳遞的參數(shù),這是您在屏幕上看到的可執(zhí)行路徑。

因此,為了能夠定義,修改,取消設(shè)置和導(dǎo)出Shell變量,我們首先需要實(shí)現(xiàn)符號(hào)表。讓我們看看接下來(lái)如何做。

  實(shí)施符號(hào)表

有多種方法可以實(shí)現(xiàn)符號(hào)表,常見(jiàn)的方法是鏈表,哈希表和二進(jìn)制搜索樹(shù)。每種方法都有優(yōu)點(diǎn)和缺點(diǎn),我們沒(méi)有時(shí)間或空間來(lái)詳細(xì)討論每種方法。為了我們的目的,我們將使用鏈表,鏈表是最容易實(shí)現(xiàn)的,并且在訪問(wèn)速度和內(nèi)存使用方面都相當(dāng)不錯(cuò)。

(注:如果你想使用的外殼任何東西比學(xué)習(xí)其他的,你應(yīng)該考慮改變符號(hào)表執(zhí)行到使用哈希表或二進(jìn)制樹(shù)可以找到哈希表實(shí)現(xiàn)的例子這里)。

現(xiàn)在,讓我們來(lái)破解該代碼。在您的源目錄中,創(chuàng)建一個(gè)名為symtab (調(diào)用 mkdir symtab從您的終端仿真器)。導(dǎo)航到該目錄(cd symtab)并創(chuàng)建一個(gè)名為 symtab.h。將以下代碼添加到剛創(chuàng)建的頭文件中:

#ifndef SYMTAB_H

#define SYMTAB_H

#include "../node.h"

#define MAX_SYMTAB 256

/* the type of a symbol table entry's value */

enum symbol_type_e

{

SYM_STR ,

SYM_FUNC,

};

/* the symbol table entry structure */

struct symtab_entry_s

{

char *name;

enum symbol_type_e val_type;

char *val;

unsigned int flags;

struct symtab_entry_s *next;

struct node_s *func_body;

};

/* the symbol table structure */

struct symtab_s

{

int level;

struct symtab_entry_s *first, *last;

};

/* values for the flags field of struct symtab_entry_s */

#define FLAG_EXPORT (1 << 0) /* export entry to forked commands */

/* the symbol table stack structure */

struct symtab_stack_s

{

int symtab_count;

struct symtab_s *symtab_list[MAX_SYMTAB];

struct symtab_s *global_symtab, *local_symtab;

};

struct symtab_s *new_symtab(int level);

struct symtab_s *symtab_stack_push(void);

struct symtab_s *symtab_stack_pop(void);

int rem_from_symtab(struct symtab_entry_s *entry, struct symtab_s *symtab);

struct symtab_entry_s *add_to_symtab(char *symbol);

struct symtab_entry_s *do_lookup(char *str, struct symtab_s *symtable);

struct symtab_entry_s *get_symtab_entry(char *str);

struct symtab_s *get_local_symtab(void);

struct symtab_s *get_global_symtab(void);

struct symtab_stack_s *get_symtab_stack(void);

void init_symtab(void);

void dump_local_symtab(void);

void free_symtab(struct symtab_s *symtab);

void symtab_entry_setval(struct symtab_entry_s *entry, char *val);

#endif

的 symbol_type_e枚舉定義了我們的符號(hào)表?xiàng)l目的類(lèi)型。我們將使用類(lèi)型SYM_STR 表示外殼變量,以及 SYM_FUNC 表示函數(shù)(在本系列后面的部分中,我們將介紹shell函數(shù))。

的 struct symtab_entry_s結(jié)構(gòu)代表我們的符號(hào)表?xiàng)l目。該結(jié)構(gòu)包含以下字段:

.name =>此條目表示的shell變量(或函數(shù))的名稱(chēng)。

.val_type => SYM_STR 對(duì)于外殼變量, SYM_FUNC 用于外殼函數(shù)。

.val =>字符串值(僅適用于Shell變量)。

.flags =>表示我們將分配給變量和函數(shù)的不同屬性,例如export和readonly標(biāo)志(我們將在本系列的后面部分處理這些標(biāo)志)。

.next =>指向下一個(gè)符號(hào)表?xiàng)l目的指針(因?yàn)槲覀儗⒈韺?shí)現(xiàn)為單鏈接列表)。

.func_body=>對(duì)于外殼函數(shù),是函數(shù)主體的抽象語(yǔ)法樹(shù)或AST(我們?cè)诒窘坛痰牡谝徊糠种杏懻摿薃ST )。

的 struct symtab_s結(jié)構(gòu)表示單個(gè)符號(hào)表。首先,我們將使用一個(gè)符號(hào)表,在其中定義所有的shell變量。稍后,當(dāng)我們討論外殼函數(shù)并開(kāi)始使用腳本文件時(shí),我們將需要定義更多的符號(hào)表。

第零個(gè)符號(hào)表將是全局表,在其中我們將定義全局變量(shell可以訪問(wèn)的全局變量,以及由它執(zhí)行的所有函數(shù)和腳本)。

符號(hào)表中排名第一的符號(hào)表是本地表,我們將在其中定義我們的本地變量(這些變量只能由聲明了它們的shell函數(shù)或腳本訪問(wèn))。通過(guò)以這種方式級(jí)聯(lián)符號(hào)表,我們有效地實(shí)現(xiàn)了變量作用域。

我們的 struct symtab_s 結(jié)構(gòu)包含以下字段:

.level =>對(duì)于全局符號(hào)表為0,對(duì)于局部符號(hào)表為1及更高。

.first, last =>分別指向表的鏈表中第一個(gè)和最后一個(gè)條目的指針。

現(xiàn)在,要能夠如上所述層疊符號(hào)表,我們需要定義并實(shí)現(xiàn)符號(hào)表?xiàng)!<锥褩J且粋€(gè)后進(jìn)先出,或LIFO,數(shù)據(jù)結(jié)構(gòu),其中的最后一個(gè)項(xiàng)目中加入(或推)是移除(或第一項(xiàng)彈出)。的struct symtab_stack_s結(jié)構(gòu)代表我們的符號(hào)表堆棧。該結(jié)構(gòu)包含以下字段:

.symtab_count =>當(dāng)前堆棧中符號(hào)表的數(shù)量。

.symtab_list=>指向堆棧符號(hào)表的指針數(shù)組。第零項(xiàng)指向全局符號(hào)表,而symtab_count-1項(xiàng)目指向最后一個(gè)(或本地)符號(hào)表。堆棧最多可容納MAX_SYMTAB 項(xiàng),我們?cè)陬^文件的開(kāi)頭將其定義為256。

.global_symtab, local_symtab =>分別指向全局和局部符號(hào)表的指針(為了易于訪問(wèn))。

我們將在本課程的稍后部分實(shí)現(xiàn)堆?!,F(xiàn)在,我們將從編寫(xiě)使用符號(hào)表所需的功能開(kāi)始。

  符號(hào)表功能

創(chuàng)建 symtab.c 文件(在 symtab 子目錄),然后添加以下代碼開(kāi)始:

#include

#include

#include

#include "../shell.h"

#include "../node.h"

#include "../parser.h"

#include "symtab.h"

struct symtab_stack_s symtab_stack;

int symtab_level;

void init_symtab(void)

{

symtab_stack.symtab_count = 1;

symtab_level = 0;

struct symtab_s *global_symtab = malloc(sizeof(struct symtab_s));

if(!global_symtab)

{

fprintf(stderr, "fatal error: no memory for global symbol table ");

exit(EXIT_FAILURE);

}

memset(global_symtab, 0, sizeof(struct symtab_s));

symtab_stack.global_symtab = global_symtab;

symtab_stack.local_symtab = global_symtab;

symtab_stack.symtab_list[0] = global_symtab;

global_symtab->level = 0;

}

首先,我們有兩個(gè)全局變量:

.symtab_stack =>指向符號(hào)表堆棧的指針(每個(gè)外殼僅需要一個(gè)堆棧)。

.symtab_level =>我們當(dāng)前在堆棧中的級(jí)別(如果正在使用全局符號(hào)表,則為0,否則為非零)。

的 init_symtab() 函數(shù)初始化符號(hào)表堆棧,然后為全局符號(hào)表分配內(nèi)存并進(jìn)行初始化。

接下來(lái),添加以下功能:

struct symtab_s *new_symtab(int level)

{

struct symtab_s *symtab = malloc(sizeof(struct symtab_s));

if(!symtab)

{

fprintf(stderr, "fatal error: no memory for new symbol table ");

exit(EXIT_FAILURE);

}

memset(symtab, 0, sizeof(struct symtab_s));

symtab->level = level;

return symtab;

}

我們稱(chēng) new_symtab() 每當(dāng)我們想要?jiǎng)?chuàng)建一個(gè)新的符號(hào)表時(shí)(例如,當(dāng)我們要執(zhí)行一個(gè)shell函數(shù)時(shí)),函數(shù)就起作用。

接下來(lái),添加以下功能:

void free_symtab(struct symtab_s *symtab)

{

if(symtab == NULL)

{

return;

}

struct symtab_entry_s *entry = symtab->first;

while(entry)

{

if(entry->name)

{

free(entry->name);

}

if(entry->val)

{

free(entry->val);

}

if(entry->func_body)

{

free_node_tree(entry->func_body);

}

struct symtab_entry_s *next = entry->next;

free(entry);

entry = next;

}

free(symtab);

}

我們稱(chēng) free_symtab() 當(dāng)我們完成了符號(hào)表的工作后,我們想使用該函數(shù),并希望釋放符號(hào)表及其條目所使用的內(nèi)存。

接下來(lái),我們將定義一個(gè)調(diào)試功能:

void dump_local_symtab(void)

{

struct symtab_s *symtab = symtab_stack.local_symtab;

int i = 0;

int indent = symtab->level * 4;

fprintf(stderr, "%*sSymbol table [Level %d]: ", indent, " ", symtab->level);

fprintf(stderr, "%*s=========================== ", indent, " ");

fprintf(stderr, "%*s No Symbol Val ", indent, " ");

fprintf(stderr, "%*s------ -------------------------------- ------------ ", indent, " ");

struct symtab_entry_s *entry = symtab->first;

while(entry)

{

fprintf(stderr, "%*s[%04d] %-32s '%s' ", indent, " ",

i++, entry->name, entry->val);

entry = entry->next;

}

fprintf(stderr, "%*s------ -------------------------------- ------------ ", indent, " ");

}

此功能打印本地符號(hào)表的內(nèi)容。當(dāng)我們的外殼啟動(dòng)時(shí),本地和全局符號(hào)表將引用同一表。只有在Shell要運(yùn)行Shell函數(shù)或腳本文件時(shí),我們的本地表才與全局表不同。(在本課程后面,我們將編寫(xiě)一個(gè)內(nèi)置實(shí)用程序,該實(shí)用程序?qū)⒄{(diào)用dump_local_symtab() 以幫助我們可視化外殼的全局符號(hào)表的內(nèi)容)。

現(xiàn)在,讓我們定義一些函數(shù)來(lái)幫助我們處理符號(hào)表?xiàng)l目。在同一文件中(symtab.c),添加以下功能:

struct symtab_entry_s *add_to_symtab(char *symbol)

{

if(!symbol || symbol[0] == '

主站蜘蛛池模板: 襄汾县| 久治县| 青海省| 应用必备| 乌鲁木齐县| 乐清市| 香港 | 福安市| 新竹市| 武山县| 广灵县| 吴旗县| 平乐县| 双柏县| 山阳县| 邯郸县| 罗平县| 监利县| 财经| 墨江| 双牌县| 内丘县| 饶平县| 深水埗区| 龙游县| 仙游县| 乳山市| 岳池县| 通海县| 郯城县| 亳州市| 临城县| 华坪县| 汉阴县| 茌平县| 水城县| 宜城市| 精河县| 金湖县| 拜城县| 辽中县|