我在c中编写了一个令牌化器,用于标记shell命令语言输入,当我执行命令时,我得到的输出是"错误的顺序"在fork
之后,如果我执行fork和exec
,则fork和exec的输出可能会在某个其他函数的循环中间出现。我想要的预期输出是
$ ls openshell.*|grep o
{ls} {openshell.cbp} {|} {grep} {o} {|}
p[0][0] ls
p[0][1] openshell.cbp
p[1][0] grep
p[1][1] o
17109: executing ls
17108: executing grep
openshell.cbp
而我得到的输出是
$ ls openshell.*|grep o
{ls} {openshell.cbp} {|} {grep} {o} {|}
p[0][0] ls
p[0][1] openshell.cbp
17108: executing grep
p[1][0] grep
openshell.cbp
17109: executing ls
p[1][1] o
执行此操作的一些代码是
static int runCmd(const char *cmd) {
const char *cp;
pid_t pid;
int status;
struct command shellcommand[4];
char **argv = 0;
int argc = 1;
bool pipe = false;
char *pString[75][75];
char *command[40];
char *command2[40];
int i1 = 0;
char **tokens;
char tokenscopy[75];
bool keep = false;
char *conc[75];
char *conc2[75];
*conc = "\0";
*conc2 = "\0";
char temp[75] = {'\0'};
int w = 0;
bool quoted = false;
int j = 0;
int i;
int p = 0;
char **ptr;
char *tmpchar;
char *cmdtmp;
bool change = false;
int f = 0;
char *char2;
int y = 0;
for (int i = 0; i < 75; i++) { /* for each pipeline */
for (int j = 0; j < 75; j++) { /* for each pipeline */
pString[i][j] = '\0';
}
}
for (cp = cmd; *cp; cp++) {
if ((*cp >= 'a') && (*cp <= 'z')) {
continue;
}
if ((*cp >= 'A') && (*cp <= 'Z')) {
continue;
}
if (isDecimal(*cp)) {
continue;
}
if (isBlank(*cp)) {
continue;
}
if ((*cp == '.') || (*cp == '/') || (*cp == '-') ||
(*cp == '+') || (*cp == '=') || (*cp == '_') ||
(*cp == ':') || (*cp == ',') || (*cp == '\'') ||
(*cp == '"')) {
continue;
}
}
char a[20] = {0};
cmdtmp = malloc(sizeof(cmd));
strcpy(cmdtmp, cmd);
tmpchar = malloc(sizeof(cmd));
strcpy(tmpchar, cmd);
tokens = str_split(command, cmdtmp, '|');
if (strstr(cmd, "|") == NULL) {
/* not a pipeline */
makeArgs(cmd, &argc, (const char ***) &argv, pipe, 0, 0);
/*dump_argv((const char *) "d", argc, argv);*/
for (j = 0; j < argc; j++) {
pString[0][j] = argv[j];
shellcommand[i].argv = pString[0]; /*command;*/
}
}
else {
i1 = 1;
for (i = 0; *(tokens + i); i++) { /* for each pipeline*/
i1++;
int e = 0;
*conc2 = "\0";
strcpy(tokenscopy, *(tokens + i));
if ((tokenscopy[0] != '\0') && !isspace(tokenscopy[0])) {
ptr = str_split(command2, *(&tokenscopy), ' ');
f = 0;
int j2 = 0;
for (j = 0; *(ptr + j); j++) {
if (ptr + j && !quoted && strstr(*(ptr + j), "'")) {
quoted = true;
strcpy(temp, *(ptr + j));
if(y<1) {
/* pString[i][j] = temp;*/
y++;
}
}
while (quoted) {
if (*(ptr + j) && strstr(*(ptr + j), "'")) { /* end of quote */
quoted = false;
if(y<1) {
pString[i][j] = strcpy(temp, *(ptr + j));
}
y=0;
}
else if (*(ptr + j)) { /* read until end of quote */
pString[i][j] = temp;
continue;
} else {
quoted = false;
break;
}
}
if (ptr + j) {
if (*(ptr + j)[0] == '{') {
keep = true;
}
if (testFn(*(ptr + j))) { /* test for last char */
pString[i][j - p] = concat(*conc, *(ptr + j));
keep = false;
free(*conc);
goto mylabel;
}
if (keep) {
*conc = concat(*conc, *(ptr + j));
*conc = concat(*conc, " ");
p++;
} else {
if (*(ptr + j + f + 1) == NULL)
break;
strcpy(temp, *(ptr + j));
change = false;
for (e = 0; *(ptr + j + e); e++) {
change = true;
if (*(ptr + e + j)) {
*conc2 = concat(*conc2, *(ptr + e + j));
*conc2 = concat(*conc2, " ");
}
}
if (change) j++;
if (makeArgs(*conc2, &argc, (const char ***) &argv, pipe, i, j2)) {
for (int r = 0; argv[r] != NULL; r++) {
char2 = malloc(sizeof(char *));
*char2 = '0';
strcpy(char2, argv[r]);
pString[w][r] = char2;
}
w++;
dump_argv((const char *) "d", argc, argv);
} else {
if (!change) {
for (int r = 0; argv[r] != NULL; r++) {
pString[i][r] = argv[r];
}
}
}
}
}
}
mylabel:
free(ptr);
}
}
free(tokens);
free(cmdtmp);
free(tmpchar);
for (i = 0; i < i1 - 1; i++) {
for (j = 0; pString[i][j] != 0; j++) {
printf("\np[%d][%d] %s", i, j, pString[i][j]);
}
shellcommand[i].argv = pString[i];
}
}
pid = fork();
if (pid < 0) {
perror("fork failed");
return -1;
}
/* If we are the child process, then go execute the pString.*/
if (pid == 0) {
/* spawn(cmd);*/
fork_pipes(i1 - 1, shellcommand);
}
/*
* We are the parent process.
* Wait for the child to complete.
*/
status = 0;
while (((pid = waitpid(pid, &status, 0)) < 0) && (errno == EINTR));
if (pid < 0) {
fprintf(stderr, "Error from waitpid: %s", strerror(errno));
return -1;
}
if (WIFSIGNALED(status)) {
fprintf(stderr, "pid %ld: killed by signal %d\n",
(long) pid, WTERMSIG(status));
return -1;
}
return WEXITSTATUS(status);
}
fork_pipes
/* Helper function that forks pipes */
void fork_pipes(int n, struct command *cmd) {
int i;
int in = 0;
int fd[2];
for (i = 0; i < n - 1; ++i) {
if (pipe(fd) == -1) {
err_syserr("Failed creating pipe");
}
spawn_proc(in, fd[1], cmd + i);
close(fd[1]);
in = fd[0];
}
if (dup2(in, 0) < 0) {
err_syserr("dup2() failed on stdin for %s: ", cmd[i].argv[0]);
}
fprintf(stderr, "%d: executing %s\n", (int) getpid(), cmd[i].argv[0]);
execvp(cmd[i].argv[0], cmd[i].argv);
err_syserr("failed to execute %s: ", cmd[i].argv[0]);
}
/* Helper function that spawns processes */
int spawn_proc(int in, int out, struct command *cmd) {
pid_t pid;
pid = fork();
if (pid == 0) {
if (in != 0) {
if (dup2(in, 0) < 0)
err_syserr("dup2() failed on stdin for %s: ", cmd->argv[0]);
close(in);
}
if (out != 1) {
if (dup2(out, 1) < 0)
err_syserr("dup2() failed on stdout for %s: ", cmd->argv[0]);
close(out);
}
fprintf(stderr, "%d: executing %s\n", (int) getpid(), cmd->argv[0]);
execvp(cmd->argv[0], cmd->argv);
err_syserr("failed to execute %s: ", cmd->argv[0]);
}
else if (pid < 0) {
err_syserr("fork failed: ");
} else {
/* printf("** we are the parent ***"); */
}
return pid;
}
在我的代码中修复它并不是绝对必要但我想知道为什么我不能期望输出是&#34;直接&#34;当我跑叉子的时候。
答案 0 :(得分:2)
原因是标准输出通常是行缓冲的,您需要一个新行来刷新输出,例如printf("p[%d][%d] %s\n", i, j, pString[i][j]);
。