为了学习,我必须用C制作外壳
我想解析一个shell命令
我的函数parse_sequence
输出一个command_t *,它是一个包含以下内容的结构:
char *program_name;
int fd_input;
bool override;
int fd_output;
bool heredoc_mode;
char **args;
command_t *next; // kind of linked_list
我所说的序列是带有重定向和管道的命令
序列被&&
,||
和;
削减
ls > file | sort
是单个序列,其中ls && echo OK
由两个序列组成
我在两种实现解析的方法之间犹豫不决
将此视为伪代码
第一种方式:递归
command_t *parse_sequence(char *sequence)
{
command_t *ret = malloc(sizeof(command_t));
char **tokens = split(sequence);
int i = 0;
while (tokens[i]) {
if (!strcmp(commands[i], "<")) {
// set input file (open commands[i + 1])
}
if (!strcmp(commands[i], ">")) {
// set output file (open commands[i + 1])
}
if (!strcmp(commands[i], "|")) {
// recursion: ret->next = parse_sequence(tokens[i + 1]);
}
else {
if (i == 0)
// set program name
else
// append args
}
}
return (ret);
}
示例:ls > file | sort --rev
i == 0: ls is set as program_name
i == 1: ++i (file) is opened and set as output file descriptor (using dup2)
i == 3: *recursion and setup pipe*
// in the recursive call commands[0] is "sort"
(recursion) i == 0: set program name
(recursion) i == 1: append argument "--rev"
(recursion) i == 2: exit function because commands[i] == NULL
第二种方式:使用管道作为分隔符分割每个命令
command_t *parse_sequence(char *sequence)
{
command_t *ret = malloc(sizeof(command_t));
command_t current_command = ret;
char **tokens = split_tokens(sequence, (char **){"|", NULL});
int i = 0;
while (commands[i]) {
if (!strcmp(commands[i], "<")) {
// set input file (open commands[++i])
}
if (!strcmp(commands[i], ">")) {
// set output file (open commands[++i])
}
if (!strcmp(commands[i], "|") // tokens are kept when splitting
// setup pipe
// current_command = current_command->next
// i++
else {
if (i > 0 && commands[i - 1] pipe or redirection)
// set program name
else
// append args
}
}
return (ret);
}
示例:ls > file | sort --rev
i == 0: ls is set as program_name
i == 1: ++i (file) is opened and set as output file descriptor (using dup2)
i == 3: *setup pipe* and current_command = current_command->next
i == 4: set program name
i == 5: append argument "--rev"
i == 6: exit function because commands[i] == NULL
两种方法中哪一种是最好的? 我会遇到什么问题?
我知道我的示例在tcsh中是错误的,但这对我的问题并不重要
我的时间很少,所以我想要最快的实施方式
谢谢!