如何在 Linux 中从 C 执行 shell 脚本?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3736210/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 23:34:30  来源:igfitidea点击:

How to execute a shell script from C in Linux?

clinuxshell

提问by Jan Deinhard

How can I execute a shell script from C in Linux?

如何在 Linux 中从 C 执行 shell 脚本?

采纳答案by nategoose

It depends on what you want to do with the script (or any other program you want to run).

这取决于您想对脚本(或您想运行的任何其他程序)做什么。

If you just want to run the script systemis the easiest thing to do, but it does some other stuff too, including running a shell and having it run the command (/bin/sh under most *nix).

如果你只想运行脚本system是最简单的事情,但它也会做一些其他的事情,包括运行 shell 并让它运行命令(大多数 *nix 下的 /bin/sh)。

If you want to either feed the shell script via its standard input or consume its standard output you can use popen(and pclose) to set up a pipe. This also uses the shell (/bin/sh under most *nix) to run the command.

如果您想通过其标准输入提供 shell 脚本或使用其标准输出,您可以使用popen(和pclose) 来设置管道。这也使用 shell(大多数 *nix 下的 /bin/sh)来运行命令。

Both of these are library functions that do a lot under the hood, but if they don't meet your needs (or you just want to experiment and learn) you can also use system calls directly. This also allows you do avoid having the shell (/bin/sh) run your command for you.

这两个都是在底层做了很多事情的库函数,但是如果它们不能满足您的需求(或者您只是想尝试和学习),您也可以直接使用系统调用。这也使您可以避免让 shell (/bin/sh) 为您运行命令。

The system calls of interest are fork, execve, and waitpid. You may want to use one of the library wrappers around execve(type man 3 execfor a list of them). You may also want to use one of the other wait functions (man 2 waithas them all). Additionally you may be interested in the system calls cloneand vforkwhich are related to fork.

感兴趣的系统调用forkexecvewaitpid。您可能想要使用其中一个库包装器execve(键入man 3 exec它们的列表)。您可能还想使用其他等待函数之一(man 2 wait全部都有)。此外,您可能感兴趣的系统调用clonevfork这些叉相关。

forkduplicates the current program, where the only main difference is that the new process gets 0 returned from the call to fork. The parent process gets the new process's process id (or an error) returned.

fork复制当前程序,其中唯一的主要区别是新进程从对 fork 的调用返回 0。父进程获取返回的新进程的进程 ID(或错误)。

execvereplaces the current program with a new program (keeping the same process id).

execve用新程序替换当前程序(保持相同的进程 ID)。

waitpidis used by a parent process to wait on a particular child process to finish.

waitpid父进程使用它来等待特定的子进程完成。

Having the fork and execve steps separate allows programs to do some setup for the new process before it is created (without messing up itself). These include changing standard input, output, and stderr to be different files than the parent process used, changing the user or group of the process, closing files that the child won't need, changing the session, or changing the environmental variables.

将 fork 和 execve 步骤分开允许程序在创建新进程之前对其进行一些设置(而不会弄乱自己)。这些包括将标准输入、输出和 stderr 更改为与使用的父进程不同的文件、更改进程的用户或组、关闭子进程不需要的文件、更改会话或更改环境变量。

You may also be interested in the pipeand dup2system calls. pipecreates a pipe (with both an input and an output file descriptor). dup2duplicates a file descriptor as a specific file descriptor (dupis similar but duplicates a file descriptor to the lowest available file descriptor).

您可能还对pipedup2系统调用感兴趣。 pipe创建一个管道(带有输入和输出文件描述符)。 dup2将文件描述符复制为特定文件描述符(dup类似于但将文件描述符复制到最低可用文件描述符)。

回答by Matthew Flaschen

You can use system:

您可以使用system

system("/usr/local/bin/foo.sh");

This will block while executing it using sh -c, then return the status code.

这将在使用 执行时阻塞sh -c,然后返回状态代码。

回答by doron

If you need more fine-grade control, you can also go the forkpipeexecroute. This will allow your application to retrieve the data outputted from the shell script.

如果你需要更精细的控制,你也可以走这forkpipeexec条路线。这将允许您的应用程序检索从 shell 脚本输出的数据。

回答by pmg

If you're ok with POSIX, you can also use popen()/pclose()

如果你对 POSIX 没问题,你也可以使用popen()/pclose()

#include <stdio.h>
#include <stdlib.h>

int main(void) {
/* ls -al | grep '^d' */
  FILE *pp;
  pp = popen("ls -al", "r");
  if (pp != NULL) {
    while (1) {
      char *line;
      char buf[1000];
      line = fgets(buf, sizeof buf, pp);
      if (line == NULL) break;
      if (line[0] == 'd') printf("%s", line); /* line includes '\n' */
    }
    pclose(pp);
  }
  return 0;
}

回答by molnarg

I prefer fork + execlp for "more fine-grade" control as doron mentioned. Example code shown below.

正如 doron 所提到的,我更喜欢 fork + execlp 来实现“更精细”的控制。示例代码如下所示。

Store you command in a char array parameters, and malloc space for the result.

将您的命令存储在字符数组参数中,并为结果分配 malloc 空间。

int fd[2];
pipe(fd);
if ( (childpid = fork() ) == -1){
   fprintf(stderr, "FORK failed");
   return 1;
} else if( childpid == 0) {
   close(1);
   dup2(fd[1], 1);
   close(fd[0]);
   execlp("/bin/sh","/bin/sh","-c",parameters,NULL);
}
wait(NULL);
read(fd[0], result, RESULT_SIZE);
printf("%s\n",result);

回答by Ganesh

A simple way is.....

一个简单的方法是......

#include <stdio.h>
#include <stdlib.h>


#define SHELLSCRIPT "\
#/bin/bash \n\
echo \"hello\" \n\
echo \"how are you\" \n\
echo \"today\" \n\
"
/*Also you can write using char array without using MACRO*/
/*You can do split it with many strings finally concatenate 
  and send to the system(concatenated_string); */

int main()
{
    puts("Will execute sh with the following script :");
    puts(SHELLSCRIPT);
    puts("Starting now:");
    system(SHELLSCRIPT);    //it will run the script inside the c code. 
    return 0;
}

Say thanks to
Yoda @http://www.unix.com/programming/216190-putting-bash-script-c-program.html


谢尤达@ http://www.unix.com/programming/216190-putting-bash-script-c-program.html