2010-09-17 3 views

ответ

38

Это зависит от того, что вы хотите сделать с помощью сценария (или любой другой программы, которую вы хотите запустить).

Если вы просто хотите запустить скрипт system, это самая простая задача, но он также выполняет некоторые другие функции, включая запуск оболочки и выполнение этой команды (/ bin/sh при большинстве * nix).

Если вы хотите либо загрузить сценарий оболочки через стандартный ввод, либо использовать его стандартный вывод, вы можете использовать popenpclose) для настройки трубы. Для запуска этой команды также используется оболочка (/ bin/sh при большинстве * nix).

Обе из них - это функции библиотеки, которые многое делают под капотом, но если они не соответствуют вашим потребностям (или вы просто хотите поэкспериментировать и учиться), вы также можете использовать системные вызовы напрямую. Это также позволяет избежать использования командной оболочки (/ bin/sh) для вас.

Запросы цен-предложений fork, execve и waitpid. Вы можете использовать одну из оберток библиотеки около execve (введите список man 3 exec). Вы также можете использовать одну из других функций ожидания (man 2 wait есть все). Кроме того, вас могут заинтересовать системные вызовы clone и vfork, которые связаны с вилкой.

fork дублирует текущую программу, где единственным основным отличием является то, что новый процесс получает 0, возвращенный из вызова в fork. Родительский процесс возвращает идентификатор процесса нового процесса (или ошибку).

execve заменяет текущую программу новой программой (сохраняя тот же идентификатор процесса).

waitpid используется родительским процессом для ожидания завершения определенного дочернего процесса.

Имея разметку fork и execve позволяет программам выполнять некоторую настройку для нового процесса до его создания (без испорчения). Они включают в себя изменение стандартного ввода, вывода и stderr для разных файлов, чем используемый родительский процесс, изменение пользователя или группы процесса, закрытие файлов, которые не нужны ребенку, изменение сеанса или изменение переменных окружения.

Вы также можете быть заинтересованы в системных вызовах pipe и dup2. pipe создает канал (как с входным, так и с дескриптором выходного файла).dup2 дублирует файловый дескриптор как специфический дескриптор файла (dup похож, но дублирует файловый дескриптор на наименьший доступный дескриптор файла).

+2

Стоит также отметить, что fork() довольно дешев, поскольку память копируется на запись и не дублируется, как только вилки программы. – Cercerilla

+0

Я большой поклонник fork/exec - он позволяет вам избегать безвредности для окружающей среды о том, что будет работать. Но можете ли вы напрямую использовать его в сценариях оболочки? Как вы говорите, используя exec, вы «избегаете использования командной оболочки (/ bin/sh) для вас»; Вам не нужно, чтобы exec/bin/sh запускал сценарий оболочки? –

+1

@Tom Anderson: Если сценарий оболочки имеет разрешения на выполнение для эффективного пользователя и имеет соответствующую первую строку shabang, в которой перечисляется файл, который эффективный пользователь также имеет разрешение на выполнение, а также сам по себе не является скриптом какого-либо типа, тогда ядро ​​будет вызовите файл, указанный в строке shabang, с файлом сценария. Если shabang скрипта был '#!/Bin/csh', тогда'/bin/sh' не запускался в сценарии fork/exec. Если это было '#!/Bin/sh', то это было бы в сценарии fork/exec, но с' system' version '/ bin/sh' будет запускаться дважды для этого скрипта. – nategoose

23

Вы можете использовать system:

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

Это будет блокировать при выполнении его с помощью sh -c, а затем вернуть код состояния.

+3

+1 Не забудьте включить '' (HTTP: // linux.die.net/man/3/system) – pmg

+1

... если у него есть исполняемый бит и строка shebang. В общем, 'system ("/bin/sh /usr/local/bin/foo.sh ");'. Да, это на самом деле называет оболочку дважды. –

1

Если вам нужен более тонкий контроль, вы также можете перейти по маршруту forkpipeexec. Это позволит вашему приложению получать данные, выводимые из сценария оболочки.

15

Если вы нормально с 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; 
} 
+0

Благодарим вас за этот пример кода. –

1

Я предпочитаю fork + execlp для «более тонкого» управления, поскольку упомянутый дорон. Пример кода, показанного ниже.

Сохраните команду в параметрах массива символов и пространстве 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); 
+0

'close (1);' не требуется, поскольку dup2() закрывает newfd самостоятельно, прежде чем переустанавливать его. – FedericoCapaldo

2

Простой способ .....

#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

Смежные вопросы