本文对bash的源码(版本:4.2.46(1)-release
)进行简要分析。
数据结构
bash是用C语言写成的,其源码中只使用了少量的数据结构:数组
,树
,单向链表
,双向链表
和哈希表
。几乎所有的bash结构都是用这些基本结构实现的。
源码中最主要的结构都定义在根目录下头文件command.h
中。
单词
bash在不同阶段传输信息并处理数据单元的数据结构是WORD_DESC
:
typedef struct word_desc {
char *word; /* Zero terminated string. */
int flags; /* Flags associated with this word. */
} WORD_DESC;
WORD_DESC
表示一个单词,字符指针word
指向一个以\0结尾的字符串,整型成员flags
定义了该单词的类型。
当前源码中定义了二十多种单词类型,如W_HASDOLLAR
表示该单词包含扩展字符$
,W_ASSIGNMENT
表示该单词是一个赋值语句,W_GLOBEXP
表示该单词是路径扩展(通配符扩展)之后的结果等等。
单词被组合为简单的链表WORD_LIST
:
typedef struct word_list {
struct word_list *next;
WORD_DESC *word;
} WORD_LIST;
WORD_LIST
在shell中无处不在。一个简单的命令就是一个单词列表,展开结果同样是一个单词列表,内置命令的参数还是一个单词列表。
重定向
结构REDIRECT
描述了一条命令的重定向链表,包含指向下一个REDIRECT对象的next指针:
typedef struct redirect {
struct redirect *next; /* Next element, or NULL. */
REDIRECTEE redirector; /* Descriptor or varname to be redirected. */
int rflags; /* Private flags for this redirection */
int flags; /* Flag value for `open'. */
enum r_instruction instruction; /* What to do with the information. */
REDIRECTEE redirectee; /* File descriptor or filename */
char *here_doc_eof; /* The word that appeared in <<foo. */
} REDIRECT;
整型成员flags
定义了目标文件打开方式。
重定向描述符redirector
的类型是一个联合体REDIRECTEE
:
typedef union {
int dest; /* Place to redirect REDIRECTOR to, or ... */
WORD_DESC *filename; /* filename to redirect to. */
} REDIRECTEE;
instruction
是枚举型变量r_instruction
,它定义了一个重定向的类型:
enum r_instruction {
r_output_direction, r_input_direction, r_inputa_direction,
r_appending_to, r_reading_until, r_reading_string,
r_duplicating_input, r_duplicating_output, r_deblank_reading_until,
r_close_this, r_err_and_out, r_input_output, r_output_force,
r_duplicating_input_word, r_duplicating_output_word,
r_move_input, r_move_output, r_move_input_word, r_move_output_word,
r_append_err_and_out
};
在REDIRECTEE
中,如果重定向类型是ri_duplicating_input
或者ri_duplicating_output
则使用整型成员dest
(如果其值为负则表示错误的重定向),否则使用结构指针成员filename
。
REDIRECT结构中的字符指针成员here_doc_eof
,指定了重定向类型为Here Document
(见这里)。
命令
命令COMMAND
结构描述一条bash命令,对于复合命令
,其内部可能还包含有其他命令:
typedef struct command {
enum command_type type; /* FOR CASE WHILE IF CONNECTION or SIMPLE. */
int flags; /* Flags controlling execution environment. */
int line; /* line number the command starts on */
REDIRECT *redirects; /* Special redirects for FOR CASE, etc. */
union {
struct for_com *For;
struct case_com *Case;
struct while_com *While;
struct if_com *If;
struct connection *Connection;
struct simple_com *Simple;
struct function_def *Function_def;
struct group_com *Group;
#if defined (SELECT_COMMAND)