Unix execv调用仅在首次运行时发生

时间:2014-05-22 02:04:53

标签: c unix

我正在编写一个C程序,该程序应该接受其命令行参数,打印它们,删除末尾的两个参数,然后重复直到没有参数保留。例如,调用

a.out alpha beta gamma delta epsilon zeta eta

应打印以下内容:

alpha beta gamma delta epsilon zeta eta
beta gamma delta epsilon zeta
gamma delta epsilon
delta

我提出的代码如下:

int main(int argc, char **argv) {
   char **ptr;

   for (ptr = argv+1; *ptr; ptr++)
      printf("%s ", *ptr);
   printf("\n");

   if (argc > 3) {
       *(ptr-1)=NULL;
       execv(*argv, argv+1);
   }
   printf("Done!");

   return 0;   
}

这适用于第一个exec调用,但没有进一步的exec结果,并且给定示例的输出是

alpha beta gamma delta epsilon zeta eta
beta gamma delta epsilon zeta
Done!

我无法理解为什么。谁能看到我做错了什么?谢谢!

1 个答案:

答案 0 :(得分:4)

关于在fork之前调用execv的所有评论都是无稽之谈。在您的情况下,您不希望原始流程继续超出调用execv的位置,因此绝对没有理由致电fork

您的代码无法正常工作的原因是,在调用argv之前,execv数组设置正确。由于argv数组不正确,execv会返回错误。通常情况下,execv不会返回,但如果出现错误,execv会返回并设置errno,您可以使用perror显示该execv。因此,您应该perror execv(*argv, argv+1); perror( "execv returned" ); 一样

alpha beta gamma delta epsilon zeta eta 
beta gamma delta epsilon zeta 
execv returned: No such file or directory
Done!

然后程序的输出是

argv

那么为什么会这样呢?因为argv列表中的第一个参数是程序本身的名称。这可以通过打印整个for (ptr = argv+1; *ptr; ptr++) 列表来证明。替换此行

for (ptr = argv; *ptr; ptr++)

用这个

./a.out alpha beta gamma delta epsilon zeta eta 
alpha beta gamma delta epsilon zeta 
execv returned: No such file or directory
Done!

打印所有参数,然后输出

argv[0]

请注意,第一次运行程序时,./a.out./a.out,因此execv将作为程序名称传递给execv。但是,第二次调用alpha时,您将传递alpha作为程序的名称。由于execv不是有效的命令名(幸运的是),argv[0]失败并返回错误。

要解决此问题,您需要确保#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main( int argc, char *argv[] ) { int i; for ( i = 1; i < argc; i++ ) printf( "%s ", argv[i] ); printf( "\n" ); if ( argc <= 2 ) { printf( "Done!\n" ); return( EXIT_SUCCESS ); } argv[argc-1] = NULL; // drop the last argument argv[1] = argv[0]; // preserve the program name as the first argument execv( argv[0], &argv[1] ); perror( "execv returned" ); // should never happen return EXIT_FAILURE; // exec failed, return error } 始终是程序的名称。这是更正后的代码

{{1}}