Wie kann ich ein Shell-Skript von C in Linux ausführen?
Wie führe ich ein Shell-Skript von C in Linux aus?
Nategans
Es hängt davon ab, was Sie mit dem Skript (oder einem anderen Programm, das Sie ausführen möchten) machen möchten.
Wenn Sie nur das Skript ausführen möchten system
ist am einfachsten, aber es macht auch einige andere Dinge, einschließlich das Ausführen einer Shell und das Ausführen des Befehls (/bin/sh unter den meisten * nix).
Wenn Sie das Shell-Skript entweder über seine Standardeingabe füttern oder seine Standardausgabe verwenden möchten, können Sie verwenden popen
(und pclose
), um eine Pipe einzurichten. Dies verwendet auch die Shell (/bin/sh unter den meisten *nix), um den Befehl auszuführen.
Beides sind Bibliotheksfunktionen, die unter der Haube viel leisten, aber wenn sie Ihren Anforderungen nicht entsprechen (oder Sie nur experimentieren und lernen möchten), können Sie auch Systemaufrufe direkt verwenden. Dadurch können Sie auch vermeiden, dass die Shell (/bin/sh) Ihren Befehl für Sie ausführt.
Die Systemaufrufe von Interesse sind fork
, execve
und waitpid
. Möglicherweise möchten Sie einen der Bibliotheks-Wrapper verwenden execve
(Typ man 3 exec
für eine Liste von ihnen). Möglicherweise möchten Sie auch eine der anderen Wartefunktionen verwenden (man 2 wait
hat sie alle). Zusätzlich könnten Sie an den Systemaufrufen interessiert sein clone
und vfork
die mit Gabel verwandt sind.
fork
dupliziert das aktuelle Programm, wobei der einzige Hauptunterschied darin besteht, dass der neue Prozess 0 vom Aufruf von Fork zurückerhält. Der übergeordnete Prozess erhält die Prozess-ID des neuen Prozesses (oder einen Fehler) zurückgegeben.
execve
ersetzt das aktuelle Programm durch ein neues Programm (unter Beibehaltung der gleichen Prozess-ID).
waitpid
wird von einem übergeordneten Prozess verwendet, um auf die Beendigung eines bestimmten untergeordneten Prozesses zu warten.
Da die Fork- und Execve-Schritte getrennt sind, können Programme einige Einstellungen für den neuen Prozess vornehmen, bevor er erstellt wird (ohne sich selbst zu vermasseln). Dazu gehören das Ändern von Standardeingabe, -ausgabe und stderr in andere Dateien als der verwendete übergeordnete Prozess, das Ändern des Benutzers oder der Gruppe des Prozesses, das Schließen von Dateien, die das Kind nicht benötigt, das Ändern der Sitzung oder das Ändern der Umgebungsvariablen.
Das könnte Sie auch interessieren pipe
und dup2
Systemaufrufe. pipe
erstellt eine Pipe (mit sowohl einem Eingabe- als auch einem Ausgabedateideskriptor). dup2
dupliziert einen Dateideskriptor als einen spezifischen Dateideskriptor (dup
ist ähnlich, dupliziert aber einen Dateideskriptor auf den niedrigsten verfügbaren Dateideskriptor).
-
Es ist auch erwähnenswert, dass fork() ziemlich billig ist, da der Speicher Copy-on-Write ist und nicht dupliziert wird, sobald das Programm sich verzweigt.
– Cercerilla
17. September 2010 um 15:33 Uhr
-
Ich bin ein großer Fan von Fork/Exec – damit können Sie umgebungsbasierte Unsicherheiten darüber vermeiden, was ausgeführt werden wird. Aber können Sie es direkt in Shell-Skripten verwenden? Wie Sie sagen, vermeiden Sie durch die Verwendung von exec, dass die Shell (/bin/sh) Ihren Befehl für Sie ausführt. müssen Sie daher nicht /bin/sh ausführen, um ein Shell-Skript auszuführen?
– Tom Anderson
17. September 2010 um 16:33 Uhr
-
@Tom Anderson: Wenn für das Shell-Skript Ausführungsberechtigungen für den effektiven Benutzer festgelegt sind und eine entsprechende Shabang-erste Zeile eine Datei auflistet, für die der effektive Benutzer auch die Berechtigung zum Ausführen hat und die auch selbst kein Skript ist, wird der Kernel aufrufen die Datei, die in der Shabang-Zeile mit der Skriptdatei aufgeführt ist. Wenn das Shabang des Drehbuchs wäre
#!/bin/csh
dann/bin/sh
würde im Fork/Exec-Szenario nicht ausgeführt werden. Wenn es wäre#!/bin/sh
dann wäre es im Fork/Exec-Szenario, aber mit dersystem
Ausführung/bin/sh
würde für dieses Skript zweimal ausgeführt werden.– Nategans
17. September 2010 um 16:43 Uhr
Matthäus Flaschen
Sie können verwenden system
:
system("/usr/local/bin/foo.sh");
Dies wird während der Ausführung blockiert sh -c
und geben Sie dann den Statuscode zurück.
-
… vorausgesetzt, es hat ein ausführbares Bit und eine Shebang-Zeile. Im Algemeinen,
system("/bin/sh /usr/local/bin/foo.sh");
. Ja, das ruft die Shell tatsächlich zweimal auf.– Roman Cheplyaka
17. September 2010 um 15:07 Uhr
-
Hallo Matt. Das ist nützlich. Aber ich sehe, dass es blockiert. Wie mache ich es asynchron?
– mdasari
18. August 2018 um 22:27 Uhr
-
Selbst wenn das Skript ausführbar ist, sagt system(“script.sh”) “script.sh not found”, sogar mit absolutem Pfad. Es funktioniert nur mit system(“sh script.sh”)
– R71
24. Juni um 15:37 Uhr
pmg
Wenn Sie mit POSIX einverstanden sind, können Sie auch verwenden 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;
}
Ein einfacher Weg ist…..
#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;
}
Danke sagen
Yoda @http://www.unix.com/programming/216190-putting-bash-script-c-program.html
doron
Wenn Sie eine feinstufigere Steuerung benötigen, können Sie auch das verwenden fork
pipe
exec
Route. Dadurch kann Ihre Anwendung die vom Shell-Skript ausgegebenen Daten abrufen.
molnarg
Ich bevorzuge fork + execlp für eine “feinere” Steuerung, wie Doron erwähnt hat. Beispielcode unten gezeigt.
Speichern Sie Ihren Befehl in einem char-Array-Parameter und Malloc-Speicherplatz für das Ergebnis.
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);