使用 C 語言中的 execlp 函式
Jinku Hu
2023年10月12日
本文將演示關於如何使用 C 語言中的 execlp
函式的多種方法。
使用 execlp
在 C 語言中使用檔名執行新程式
exec
系列函式是作為低階 execve
系統呼叫的替代 API 提供的,用於管理將新程式載入到程序記憶體中。這個系列有 6 個獨立的函式,它們主要是引數不同而不是結果不同。execlp
函式是給使用者指定檔名的選項,程式會在當前 PATH
環境變數列出的目錄中搜尋。
如果檔名仍然包含斜線,則被視為相對或絕對路徑名。在下面的例子中,我們實現了一個行為類似於 shell 的程式。也就是說,它從使用者那裡獲取程式名,並作為一個子程序來執行。父程序等待,一旦子程序返回,控制權就會進入使用者輸入的下一個迭代。程式應該由使用者用Ctrl+D這樣的按鍵終止(取決於作業系統)。注意,有些 shell 命令不能執行,最重要的是,命令列引數沒有傳遞,而程式卻列印出 couldn't execute
。
#include <sys/wait.h>
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
enum { MAXLINE = 256, MAXARGS = 48 };
int main(int argc, char *argv[]) {
char buf[MAXLINE];
pid_t pid;
int status;
char *str1, *token;
printf("%% ");
while (fgets(buf, MAXLINE, stdin) != NULL) {
if (buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = 0;
if ((pid = fork()) < 0) {
perror("fork");
} else if (pid == 0) {
execlp(buf, buf, (char *)NULL);
printf("couldn't execute: %s", buf);
exit(127);
}
if (waitpid(pid, &status, 0) < 0) perror("waitpid");
printf("%% ");
}
exit(EXIT_SUCCESS);
}
execlp
是可變函式,因此,它可以接受不同數量的引數。不過第一個和最後一個引數是固定的,代表檔名的指標,而 NULL
則相應地投向 char*
。需要注意的是,強制轉換 null 指標是函式工作的必備條件,同時也表示變數引數數的結束。總之,第二個位置的引數應該指定程式的命令列引數,其中第一個引數應該是檔名本身。
另外,我們也可以實現前面的例子,能夠執行帶有引數的命令。在這種情況下,我們利用了 execvp
函式,它將引數列表作為一個陣列。同時,我們使用 strtok
來解析使用者輸入,將每個空格分隔的字串作為引數傳遞。結果,我們得到了更接近 shell 程式的模擬。
#include <sys/wait.h>
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
enum { MAXLINE = 256, MAXARGS = 48 };
int main(int argc, char *argv[]) {
char buf[MAXLINE];
char *args[MAXARGS];
pid_t pid;
int status, args_num = 0;
char *str1, *token;
printf("%% ");
while (fgets(buf, MAXLINE, stdin) != NULL) {
if (buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = 0;
str1 = strdup(buf);
for (int j = 0;; j++, str1 = NULL) {
token = strtok(str1, " ");
if (token == NULL) break;
args[j] = token;
args_num += 1;
printf("%d: %s\n", j + 1, args[j]);
}
free(str1);
args[args_num] = (char *)NULL;
if ((pid = fork()) < 0) {
perror("fork");
} else if (pid == 0) {
execvp(args[0], &args[0]);
printf("couldn't execute: %s", buf);
exit(127);
}
if (waitpid(pid, &status, 0) < 0) perror("waitpid");
printf("%% ");
}
exit(EXIT_SUCCESS);
}
作者: Jinku Hu