如何从Linux中执行一个shell脚本?

时间:2022-06-29 14:40:31

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

如何在Linux中执行C语言的shell脚本?

6 个解决方案

#1


39  

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 system is 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).

如果您只是想运行脚本系统,这是最容易的事情,但是它也做了一些其他的事情,包括运行shell并让它运行命令(/bin/sh在大多数*nix下)。

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 (/bin/sh在大多数*nix下)运行命令。

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 exec for a list of them). You may also want to use one of the other wait functions (man 2 wait has them all). Additionally you may be interested in the system calls clone and vfork which are related to fork.

系统调用的是fork、execve和waitpid。您可能希望使用execve周围的一个库包装器(类型为man 3 exec,以获得它们的列表)。您可能还想使用另一个等待函数(man 2 wait拥有它们全部)。另外,您可能对与fork相关的系统调用克隆和vfork感兴趣。

fork duplicates 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(或错误)返回。

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

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

waitpid is 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 pipe and dup2 system calls. pipe creates a pipe (with both an input and an output file descriptor). dup2 duplicates a file descriptor as a specific file descriptor (dup is similar but duplicates a file descriptor to the lowest available file descriptor).

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

#2


23  

You can use system:

您可以使用系统:

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

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

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

#3


15  

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;
}

#4


2  

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

感谢Yoda @http://www.unix.com/programming/216190-putting-bash-script-c-program.html。

#5


1  

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

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

#6


1  

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

我更喜欢用fork + execlp作为doron提到的“更精细的”控制。示例代码如下所示。

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

将命令存储在char数组参数中,并在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);

#1


39  

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 system is 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).

如果您只是想运行脚本系统,这是最容易的事情,但是它也做了一些其他的事情,包括运行shell并让它运行命令(/bin/sh在大多数*nix下)。

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 (/bin/sh在大多数*nix下)运行命令。

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 exec for a list of them). You may also want to use one of the other wait functions (man 2 wait has them all). Additionally you may be interested in the system calls clone and vfork which are related to fork.

系统调用的是fork、execve和waitpid。您可能希望使用execve周围的一个库包装器(类型为man 3 exec,以获得它们的列表)。您可能还想使用另一个等待函数(man 2 wait拥有它们全部)。另外,您可能对与fork相关的系统调用克隆和vfork感兴趣。

fork duplicates 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(或错误)返回。

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

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

waitpid is 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 pipe and dup2 system calls. pipe creates a pipe (with both an input and an output file descriptor). dup2 duplicates a file descriptor as a specific file descriptor (dup is similar but duplicates a file descriptor to the lowest available file descriptor).

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

#2


23  

You can use system:

您可以使用系统:

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

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

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

#3


15  

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;
}

#4


2  

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

感谢Yoda @http://www.unix.com/programming/216190-putting-bash-script-c-program.html。

#5


1  

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

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

#6


1  

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

我更喜欢用fork + execlp作为doron提到的“更精细的”控制。示例代码如下所示。

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

将命令存储在char数组参数中,并在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);