web-dev-qa-db-ja.com

LinuxでCからシェルスクリプトを実行する方法

LinuxでCからシェルスクリプトを実行するにはどうすればよいですか?

49
Jan Deinhard

スクリプト(または実行する他のプログラム)で何をしたいかによって異なります。

スクリプトを単に実行したい場合は、 system が最も簡単ですが、シェルの実行やコマンドの実行(/ bin /ほとんどの* nixの下でsh)。

標準入力を介してシェルスクリプトをフィードするか、標準出力を使用する場合は、popen(およびpclose)を使用してパイプをセットアップできます。また、これはコマンド(ほとんどの* nixでは/ bin/sh)を使用してコマンドを実行します。

これらはどちらも内部で多くの機能を果たすライブラリ関数ですが、ニーズに合わない場合(または実験して学習したい場合)は、システムコールを直接使用することもできます。これにより、シェル(/ bin/sh)がコマンドを実行することを回避できます。

対象のシステムコールは、forkexecve、およびwaitpidです。 execve(タイプman 3 execはそれらのリストです)。また、他の待機関数(man 2 waitにすべてあります)。さらに、フォークに関連するclonevforkのシステムコールに興味があるかもしれません。

forkは現在のプログラムを複製しますが、唯一の主な違いは、新しいプロセスがforkの呼び出しから0を返すことです。親プロセスは、新しいプロセスのプロセスID(またはエラー)を返します。

execveは、現在のプログラムを新しいプログラムに置き換えます(同じプロセスIDを保持します)。

waitpidは、特定の子プロセスの終了を待機するために親プロセスによって使用されます。

Forkとexecveのステップを別々にすると、プログラムは新しいプロセスが作成される前に(それ自体を台無しにすることなく)何らかのセットアップを行うことができます。これらには、使用される親プロセスとは異なるファイルへの標準入力、出力、および標準エラーの変更、プロセスのユーザーまたはグループの変更、子が必要としないファイルのクローズ、セッションの変更、または環境変数の変更が含まれます。

pipedup2システムコール。 pipeは、パイプを作成します(入力ファイル記述子と出力ファイル記述子の両方を使用)。 dup2は、ファイル記述子を特定のファイル記述子として複製します(dupも同様ですが、ファイル記述子を使用可能な最も低いファイル記述子に複製します)。

48
nategoose

systemを使用できます:

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

これは、sh -cを使用して実行中にブロックし、ステータスコードを返します。

25

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

簡単な方法は.....

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

おかげで言う
ヨーダ@ http://www.unix.com/programming/216190-putting-bash-script-c-program.html

3
Ganesh

Doronが述べたように、「より細かなグレード」の制御にはfork + execlpが好きです。以下にコード例を示します。

コマンドを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
GABIKA6

さらに細かな制御が必要な場合は、forkpipeexecルートに移動することもできます。これにより、アプリケーションはシェルスクリプトから出力されたデータを取得できます。

1
doron