我想执行多个命令,例如./shell ls > test.txt;ls > test1.txt;ls > test2.txt;
,它们应该在提到的文件中打印输出3次。但是,不知怎的,我的代码只打印一次。
我用';'分隔了char缓冲区使用strtok_r。
另外,我看了另一个与我的问题类似的例子: Nested strtok function problem in C
这是我的代码
void call_system(char *argv[],int argc)
{
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = child_handler;
sigaction(SIGCHLD, &sa, NULL);
int pid;
int background;
/*two process are created*/
pid=fork();
background = 0;
if(pid<0)
{
fprintf(stderr,"unsuccessful fork /n");
exit(EXIT_SUCCESS);
}
else if(pid==0)
{
chdir("h/Ravi Griffith/Sem 1-2015/SP/Assignment1/Assignment1");
char *bname;
char *path2 = strdup(*argv);
bname = basename(path2);
execvp(bname, argv);
}
else if(pid>0)
{
/*it will wait untill the child process doesn't finish*/
child_handler(pid);
exit(EXIT_SUCCESS);
}
}
int main(int argc,char *argv[])
{
if(argc>1)
{
/*it will check whether a user has entered exit then the code will be executed successfully.*/
if(strcmp( argv[1], "exit")==0)
{
exit(EXIT_SUCCESS);
}
}
else
{
printf("Enter Shell Command -- ");
char buffer[80];
fgets(buffer, sizeof(buffer), stdin);
//it will replace the newline character with null
buffer[strlen(buffer) - 1] = '\0';
char *end_str;
char* token= strtok_r(buffer, ";", &end_str);
/* string will be split in individual argument array */
while(token != NULL)
{
int i;
char *endtoken;
printf("a = %s\n", token);
char *array[strlen(buffer)];
i = 0;
char *token2 = strtok_r(token," ", &endtoken);
while (token2 != NULL)
{
array[i++] = token2;
token2 = strtok_r(NULL, " ", &endtoken);
}
if(sizeof(array)>16)
{
char *arrow=array[strlen(buffer)-1];
char *filename;
filename=array[strlen(buffer)];
/*printf("%s",arrow);
printf("%s",filename);*/
if(strcmp( arrow, ">") == 0)
{
freopen( filename, "w", stdout );
}
else if(strcmp( arrow, "<") == 0)
{
freopen( filename, "rb", stdin );
}
}
splittoarray(buffer,argv);
call_system(argv,argc);
token = strtok_r(NULL, ";",&end_str);
}
}
}
答案 0 :(得分:1)
鉴于讨论命令行以strtok_r
的嵌套方式拆分为单个参数,我将以下示例放在一起概述其对您的问题的应用。 (我已经省略了,你的具体代码与拆分无关,我已根据需要进行了更改)。原始拆分代码的最大问题是,在声明灵活的指针数组以保存指向strtok_r
返回的标记的指针之后,您只需将strtok_r
的返回值分配给指针数组,而无需分配内存和制作token/token2
指向的字符串的副本。
虽然strtok_r
将返回指向每个令牌的指针,但token
指向的内存位置可能会在下次调用strtok_r
时发生更改。因此,为了保留令牌供以后使用,您需要在下次调用token/token2
之前复制strtok_r
指向的字符串。
要注意的另一个问题是,在使用;
拆分后,当您将单个命令拆分为args时,您不能简单地传递token
令牌数组中的字符串({{1修改原始)。您必须复制strtok_r
数组中的每个字符串,并将指向该副本的指针传递给token
。这样,您可以将起始地址保留到每个已分配的strtok_r
字符串,以防止您在将指针传递给token
时使您的程序SegFault
成为free
后面。
这是一个简短的例子:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char *argv[])
{
if(argc > 1 && strcmp (argv[1], "exit")==0) {
exit(EXIT_SUCCESS);
}
printf("Enter Shell Command -- ");
char buffer[80];
fgets(buffer, sizeof(buffer), stdin);
/* replace the newline character with null */
buffer[strlen(buffer) - 1] = '\0';
char *cmdarray[strlen (buffer)];
size_t cmdidx = 0;
size_t n = 0;
char *end_str = NULL;
char* token= strtok_r(buffer, ";", &end_str);
/* initialize command string array */
for (n = 0 ; n < strlen (buffer); n++)
cmdarray[n] = NULL;
/* split into individual command string */
while (token)
{
cmdarray[cmdidx++] = strdup (token);
token = strtok_r (NULL, ";", &end_str);
}
/* loop to process command strings into args */
for (n = 0; n < cmdidx; n++)
{
size_t i = 0;
size_t cmdsz = strlen (cmdarray[n]);
size_t arridx = 0;
char *token2 = NULL;
char *endtoken = NULL;
char *array[cmdsz];
char *cmdcopy = strdup (cmdarray[n]);
char *sp = cmdcopy;
/* initialize argument array */
for (i = 0; i < cmdsz; i++)
array[i] = NULL;
/* split each command string into argument array */
for (token2 = strtok_r (sp, " ", &endtoken); token2; token2 = strtok_r (NULL, " ", &endtoken))
array[arridx++] = strdup (token2);
/* main processing of commands and args here
* (print example of all values tokenized)
*/
printf ("\ncmdarray[%zu] : %s\n", n, cmdarray[n]);
for (i = 0; i < arridx; i++)
printf (" array[%zu] : %s\n", i, array[i]);
/* free memory allocated to array */
for (i = 0; i < arridx; i++)
if (array[i])
free (array[i]);
/* free copy of command used to tokenize arguments */
if (cmdcopy)
free (cmdcopy);
}
/* free command memory */
n = 0;
while (cmdarray[n]) free (cmdarray[n++]);
return 0;
}
嵌套命令拆分示例
$ ./bin/strtok_r_nested
Enter Shell Command -- ./shell ls > test.txt;ls > test1.txt;ls > test2.txt
cmdarray[0] : ./shell ls > test.txt
array[0] : ./shell
array[1] : ls
array[2] : >
array[3] : test.txt
cmdarray[1] : ls > test1.txt
array[0] : ls
array[1] : >
array[2] : test1.txt
cmdarray[2] : ls > test2.txt
array[0] : ls
array[1] : >
array[2] : test2.txt
确认无泄漏
$ valgrind ./bin/strtok_r_nested
==19622== Memcheck, a memory error detector
==19622== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==19622== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==19622== Command: ./bin/strtok_r_nested
==19622==
Enter Shell Command -- ./shell ls > test.txt;ls > test1.txt;ls > test2.txt
<snip>
==19622==
==19622== HEAP SUMMARY:
==19622== in use at exit: 0 bytes in 0 blocks
==19622== total heap usage: 16 allocs, 16 frees, 156 bytes allocated
==19622==
==19622== All heap blocks were freed -- no leaks are possible
==19622==
==19622== For counts of detected and suppressed errors, rerun with: -v
==19622== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)