linux c程式中獲取shell指令碼輸出

2022-07-27 21:30:33 字數 3740 閱讀 7698

1. 前言

unix界有一句名言:「一行shell指令碼勝過萬行c程式」,雖然這句話有些誇張,但不可否認的是,借助指令碼確實能夠極大的簡化一些程式設計工作。比如實現乙個ping程式來測試網路的連通性,實現ping函式需要寫上200~300行**,為什麼不能直接呼叫系統的ping命令呢?通常在程式中通過 system函式來呼叫shell命令。但是,system函式僅返回命令是否執行成功,而我們可能需要獲得shell命令在控制台上輸出的結果。例如,執行外部命令ping後,如果執行失敗,我們希望得到ping的返回資訊。

2. 使用臨時檔案

首先想到的方法就是將命令輸出重定向到乙個臨時檔案,在我們的應用程式中讀取這個臨時檔案,獲得外部命令執行結果,**如下所示:

#define cmd_str_len 1024

int mysystem(char* cmdstring, char* tmpfile)

char cmd_string[cmd_str_len];

tmpnam(tmpfile);

sprintf(cmd_string, "%s > %s", cmdstring, tmpfile);

return system(cmd_string);

這種使用使用了臨時檔案作為應用程式和外部命令之間的聯絡橋梁,在應用程式中需要讀取檔案,然後再刪除該臨時檔案,比較繁瑣,優點是實現簡單,容易理解。有沒有不借助臨時檔案的方法呢?

3. 使用匿名管道

在* @param[in] cmdstring 呼叫外部程式或指令碼的命令串

* @param[out] buf 返回外部命令的結果的緩衝區

* @param[in] len 緩衝區buf的長度

*   * @return 0: 成功; -1: 失敗    */

int mysystem(char* cmdstring, char* buf, int len)

int   fd[2]; pid_t pid;

int   n, count;

memset(buf, 0, len);

if (pipe(fd) < 0)

return -1;

if ((pid = fork()) < 0)

return -1;

else if (pid > 0)     /* parent process */

close(fd[1]);     /* close write end */

count = 0;

while ((n = read(fd[0], buf + count, len)) > 0 && count > len)

count += n;

close(fd[0]);

if (waitpid(pid, null, 0) > 0)

return -1;

else    /* child process */

close(fd[0]);     /* close read end */

if (fd[1] != stdout_fileno)

if (dup2(fd[1], stdout_fileno) != stdout_fileno)

return -1;

close(fd[1]);

if (execl("/bin/sh", "sh", "-c", cmdstring, (char*)0) == -1)

return -1;

return 0;

4. 使用popen

在學習unix程式設計的過程中,發現系統還提供了乙個popen函式,可以非常簡單的處理呼叫shell,其函式原型如下:

file *popen(const char *command, const char *type);

該函式的作用是建立乙個管道,fork乙個程序,然後執行shell,而shell的輸出可以採用讀取檔案的方式獲得。採用這種方法,既避免了建立臨時檔案,又不受輸出字元數的限制,推薦使用。

popen使用fifo管道執行外部程式。

#include

file *popen(const char *command, const char *type);

int pclose(file *stream);

popen 通過type是r還是w確定command的輸入/輸出方向,r和w是相對command的管道而言的。r表示command從管道中讀入,w表示 command通過管道輸出到它的stdout,popen返回fifo管道的檔案流指標。pclose則用於使用結束後關閉這個指標。

下面看乙個例子:

#include

#include

#include

#include

#include

int main( void )

file   *stream;

file    *wstream;

char   buf[1024];

memset( buf, '/0', sizeof(buf) );//初始化buf,以免後面寫如亂碼到檔案中

stream = popen( "ls -l", "r" ); //將「ls -l」命令的輸出 通過管道讀取(「r」引數)到file* stream

wstream = fopen( "test_popen.txt", "w+"); //新建乙個可寫的檔案

fread( buf, sizeof(char), sizeof(buf), stream); //將剛剛file* stream的資料流讀取到buf中

fwrite( buf, 1, sizeof(buf), wstream );//將buf中的資料寫到file    *wstream對應的流中,也是寫到檔案中

pclose( stream );

fclose( wstream );

return 0;

[root@localhost src]# gcc popen.c

[root@localhost src]# ./a.out

[root@localhost src]# cat test_popen.txt

總計 128

-rwxr-xr-x 1 root root 5558 09-30 11:51 a.out

-rwxr-xr-x 1 root root 542 09-30 00:00 child_fork.c

-rwxr-xr-x 1 root root 480 09-30 00:13 execve.c

-rwxr-xr-x 1 root root 1811 09-29 21:33 fork.c

-rwxr-xr-x 1 root root 162 09-29 18:54 getpid.c

-rwxr-xr-x 1 root root 1105 09-30 11:49 popen.c

-rwxr-xr-x 1 root root 443 09-30 00:55 system.c

-rwxr-xr-x 1 root root    0 09-30 11:51 test_popen.txt

-rwxr-xr-x 1 root root 4094 09-30 11:39 test.txt

5. 小結

有統計資料表明,**的缺陷率是一定的,與所使用的語言無關。linux提供了很多的實用工具和指令碼,在程式中呼叫工具和指令碼,無疑可以簡化程式,從而降低**的缺陷數目。linux shell指令碼也是乙個強大的工具,我們可以根據需要編制指令碼,然後在程式中呼叫自定義指令碼。

linux C程式中獲取shell指令碼輸出

本文使用docbook書寫,您可以在這裡獲得xml 檔案 abstract 本文描述了從linux程式中執行 shell 程式 指令碼 並獲得輸出結果的方法。table of contents 1.前言 2.使用臨時檔案 3.使用匿名管道 4.使用popen 5.小結 unix界有一句名言 一行sh...

linux c程式中獲取shell指令碼輸出

1.前言 unix界有一句名言 一行shell指令碼勝過萬行c程式 雖然這句話有些誇張,但不可否認的是,借助指令碼確實能夠極大的簡化一些程式設計工 作。比如實現乙個ping程式來測試網路的連通性,實現ping函式需要寫上200 300行 為什麼不能直接呼叫系統的ping命令呢?通常在程式 中通過 s...

linux C程式中獲取shell指令碼輸出

本文使用docbook書寫,您可以在這裡獲得xml檔案 abstract 本文描述了從linux程式中執行shell 程式 指令碼 並獲得輸出結果的方法。table of contents 1.前言 2.使用臨時檔案 3.使用匿名管道 4.使用popen 5.小結 unix界有一句名言 一行shel...