c語言怎麼使用shell語言,shell腳本入門教程 c語言

本文目錄一覽:

C語言 shell命令

可以通過system函數,調用shell命令。

1 函數原型:

int system(const char *cmd);

2 功能:

調用cmd內容的系統命令,即shell命令。

3 頭文件:

stdlib.h

4 舉例:

system(“ls”);

打印當前工作目錄下的文件。

如何在C語言中執行shell命令

題主可以使用 exec 系列函數。這系列函數定義在 unistd.h 頭文件中,所以使用前請包含這個頭文件。這系列函數共有五個,

execl, execlp, execv, execvp, execle

其中常用的是前四個。前四個函數的原型為:

int execl(const char *path, const char *arg, …);

int execlp(const char *file, const char *arg, …);

int execv(const char *path, char *const argv[]);

int execvp(const char *file, char *const argv[]);

這四個函數的主要差別就在於參數的類型和用不用輸入命令的絕對路徑上。

以路徑形式來分,凡是函數名中帶 p 的(execlp,execvp)都只需要提供命令的名,函數會自動在當前的環境變量 $PATH 中查找命令的路徑。而不帶 p 的(execl,execv)必須要提供命令的絕對路徑,否則函數會找不到這個命令的位置。這裡以 execl 和 execlp 為例,以下運行

ls -l

命令的代碼:

#include stdio.h

#include unistd.h

int main() {

    // exec 系列函數出錯時會返回 -1,平常返回 0,所以可以

    // 據此來打印錯誤信息

    // 第一個 ls 是命令的名稱,execlp 函數會自動在 $PATH

    // 中尋找這個命令。

    // 後面一個 ls 是要在 shell 中輸入的第一個參數

    //(也就是命令名稱本身)

    // 使用 NULL 作為參數結尾標記是 exec 系列函數的要求。

    if (execlp(“ls”, “ls”, “-l”, NULL) == -1)

        perror(“Error Executing Command.\n”);

    return 0;

    

}

在 shell 中運行這個 C 程序會輸出

和你直接在 shell 中寫 ls -l 的效果是一樣的。然而,如果你使用不帶 p 的 execl, 那麼這樣寫就會報錯。

#include stdio.h

#include unistd.h

int main() {

    // execl 只接受命令的絕對路徑,所以必須輸入完整的

    // 路徑 /bin/ls,即

    // if (execl(“/bin/ls”, “ls”, “-l”, NULL) == -1)

    if (execl(“ls”, “ls”, “-l”, NULL) == -1)

        perror(“Error Executing Command.\n”);

    return 0;

    

}

輸出結果為:

以參數類型來分,凡是函數名中帶 l 的(execl,execlp)都需要把系統命令的參數全部傳遞給函數,而凡是函數名中帶 v 的(execv,execvp)都需要把系統命令的參數統一放在一個數組裡,然後把這個數組傳遞給函數。

比如剛才這個

#include stdio.h

#include unistd.h

int main() {

    if (execlp(“ls”, “ls”, “-l”, NULL) == -1)

        perror(“Error Executing Command.\n”);

    return 0;

    

}

如果改用 execvp 來寫的話就是

#include stdio.h

#include unistd.h

int main() {

    // 這個字符串數組存有所有參數(包括命令名本身和

    // 最後的 NULL)

    char * argv[] = {“ls”, “-l”, NULL};

    

    // 這裡只需將命令名稱和參數數組傳遞給 execvp 函數即可,

    // 無需將參數一個個傳遞。同樣函數會自動在 $PATH 

    // 中查找命令

    if (execvp(“ls”, argv) == -1)

        perror(“Error Executing Command.\n”);

    return 0;

    

}

運行結果同樣和直接寫 ls -l 的效果相同。

execv 和 execvp 的區別也在於是否必須輸入絕對路徑,就不贅述了。

要注意的一點是,如果執行成功,exec 系列函數開啟的新進程會完全代替當前的進程,也就是說當前進程會消失。所以一般會將 exec 和 fork 連用,先 fork 出一個子進程,然後在這個子進程中使用 exec 運行別的程序,防止父進程被 exec 覆蓋。比如剛才的代碼稍微改一下

#include stdio.h

#include unistd.h

int main() {

    char * argv[] = {“ls”, “-l”, NULL};

    if (execvp(“ls”, argv) == -1)

        perror(“Error Executing Command.\n”);

        

    // 加入一個 printf 語句

    printf(“Main process is still running.\n”);

    return 0;

    

}

運行後並不會出現 Main process is still running 這句話,因為 exec 後 main 函數執行產生的進程已經被 ls 命令產生的進程完全覆蓋了,所以 exec 函數以下的語句是完全不會執行的。這時就可以使用 fork 來新建一個子進程,在子進程中執行 exec 函數。

#include stdio.h

#include unistd.h

#include sys/types.h

#include sys/wait.h

int main() {

    

    int r;

    

    // fork() 大於零,父進程

    if ((r = fork())  0) {

        int status;

        if (wait(status) != -1) {

            

            // 等待子進程退出

            if(WIFEXITED(status)) {

                printf(“Main process is still running.\n”);

                return 0;

            }

        }

    

    // fork () 等於零,子進程。子進程中運行 exec    

    } else if (r == 0) {

    

        char * argv[] = {“ls”, “-l”, NULL};

        if (execvp(“ls”, argv) == -1)

            perror(“Error Executing Command.\n”);

        return 0;

    

    // fork() 小於零,出錯

    } else {

        perror(“Fork”);

    }

    

    return 0;

    

}

這樣運行結果就變成了

Main process is still running 這句話就會被輸出到屏幕上。

linux下怎樣用c語言調用shell命令

C程序調用shell腳本共同擁有三種法子 :system()、popen()、exec系列數call_exec1.c ,

system() 不用你自己去產生進程。它已經封裝了,直接增加自己的命令

exec 須要你自己 fork 進程,然後exec 自己的命令

popen() 也能夠實現運行你的命令,比system 開銷小

方法一、system()的使用。我直接上代碼吧

int system(const char *command);

我在/home/book/shell新建一個test.sh文件例如以下:

span style=”font-size:18px;”span style=”font-size:18px;”#!bin/bash

echo $HOME

echo “the is test!”/span/span

test.c文件例如以下:

span style=”font-size:18px;”span style=”font-size:18px;”#includestdlib.h

int main()

{

system(“bash /home/book/shell/test.sh”); /* chmod +x test.sh ,路徑前面要加上bash */

return 0;

}/span/span

運行例如以下命令來編譯:

span style=”font-size:18px;”gcc test.c -o test

/span

測試命令:

span style=”font-size:18px;”./test/span

結果例如以下:

span style=”font-size:18px;”/root

the is test!/span

方法二:popen() 會調用fork()產生 子歷程,然後從子歷程中調用/bin/sh -c來履行 參數command的指令。參數type可應用 “r”代表讀取。“w”代表寫入。遵循此type值。popen()會建立 管道連到子歷程的標準 輸出設備 或標準 輸入設備 ,然後返回一個文件指針。

隨後歷程便可利用 此文件指針來讀取子歷程的輸出設備 或是寫入到子歷程的標準 輸入設備 中。此外,全部應用 文 件指針(FILE*)操作的函數也都能夠應用 ,除了fclose()以外。

返回值:若成功 則返迴文件指針,否則返回NULL,差錯 原因存於errno中。注意:在編寫具SUID/SGID權限的程序時請盡量避免應用 popen()。popen()會繼承環境變量。通過環境變量可能會造成系統安全的問題

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

int pclose(FILE *stream);

其它不用改變我們直接改動test.c文件:

#includestdio.h

int main()

{

char buffer[80];

FILE *fp=popen(“bash /home/book/shell/test.sh”,”r”);

fgets(buffer,sizeof(buffer),fp);

printf(“%s”,buffer);

pclose(fp);

return 0;

}

方法三:exec函數簇 (我不太懂,copy別人的。也沒有驗證。習慣方法一)

須要注意的是exec並非1個函數, 事實上它僅僅是一組函數的統稱, 它包含以下6個函數:

#include unistd.h

int execl(const char *path, const char *arg, …);

int execlp(const char *file, const char *arg, …);

int execle(const char *path, const char *arg, …, char *const envp[]);

int execv(const char *path, char *const argv[]);

int execvp(const char *file, char *const argv[]);

int execve(const char *path, char *const argv[], char *const envp[];

能夠見到這6個函數名字不同, 並且他們用於接受的參數也不同.

實際上他們的功能都是幾乎相同的, 由於要用於接受不同的參數所以要用不同的名字區分它們, 畢竟c語言沒有函數重載的功能嘛..

可是實際上它們的命名是有規律的:

exec[l or v][p][e]

exec函數里的參數能夠分成3個部分, 運行文件部分, 命令參數部分, 環境變量部分.

比如我要運行1個命令 ls -l /home/gateman

運行文件部分就是 “/usr/bin/ls”

命令參賽部分就是 “ls”,”-l”,”/home/gateman”,NULL 見到是以ls開頭 每1個空格都必須分開成2個部分, 並且以NULL結尾的啊.

環境變量部分, 這是1個數組,最後的元素必須是NULL 比如 char * env[] = {“PATH=/home/gateman”, “USER=lei”, “STATUS=testing”, NULL};

好了說下命名規則:

e興許, 參數必須帶環境變量部分, 環境變零部分參數會成為運行exec函數期間的環境變量, 比較少用

l 興許, 命令參數部分必須以”,” 相隔, 最後1個命令參數必須是NULL

v 興許, 命令參數部分必須是1個以NULL結尾的字符串指針數組的頭部指針. 比如char * pstr就是1個字符串的指針, char * pstr[] 就是數組了, 分別指向各個字符串.

關於Linux命令的介紹,看看《linux就該這麼學》,具體關於這一章地址3w(dot)linuxprobe/chapter-02(dot)html

p興許, 運行文件部分能夠不帶路徑, exec函數會在$PATH中找

還有1個注意的是, exec函數會代替運行它的進程, 也就是說, 一旦exec函數運行成功, 它就不會返回了, 進程結束. 可是假設exec函數運行失敗, 它會返回失敗的信息, 並且進程繼續運行後面的代碼!

通常exec會放在fork() 函數的子進程部分, 來替代子進程運行啦, 運行成功後子程序就會消失, 可是運行失敗的話, 必須用exit()函數來讓子進程退出!

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/245479.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-12 13:09
下一篇 2024-12-12 13:09

相關推薦

  • Python腳本控制其他軟件

    Python作為一種簡單易學、功能強大的腳本語言,具有廣泛的應用領域,在自動化測試、Web開發、數據挖掘等領域都得到了廣泛的應用。其中,Python腳本控制其他軟件也是Python…

    編程 2025-04-29
  • AES加密解密算法的C語言實現

    AES(Advanced Encryption Standard)是一種對稱加密算法,可用於對數據進行加密和解密。在本篇文章中,我們將介紹C語言中如何實現AES算法,並對實現過程進…

    編程 2025-04-29
  • 學習Python對學習C語言有幫助嗎?

    Python和C語言是兩種非常受歡迎的編程語言,在程序開發中都扮演着非常重要的角色。那麼,學習Python對學習C語言有幫助嗎?答案是肯定的。在本文中,我們將從多個角度探討Pyth…

    編程 2025-04-29
  • Python被稱為膠水語言

    Python作為一種跨平台的解釋性高級語言,最大的特點是被稱為”膠水語言”。 一、簡單易學 Python的語法簡單易學,更加人性化,這使得它成為了初學者的入…

    編程 2025-04-29
  • Shell腳本與Python腳本的區別

    本文將從多個方面對Shell腳本與Python腳本的區別做詳細的闡述。 一、語法差異 Shell腳本和Python腳本的語法存在明顯差異。 Shell腳本是一種基於字符命令行的語言…

    編程 2025-04-29
  • OpenJudge答案1.6的C語言實現

    本文將從多個方面詳細闡述OpenJudge答案1.6在C語言中的實現方法,幫助初學者更好地學習和理解。 一、需求概述 OpenJudge答案1.6的要求是,輸入兩個整數a和b,輸出…

    編程 2025-04-29
  • Polyphone音頻編輯器基礎入門教程

    Polyphone是一款免費的音頻編輯器,可用於編輯.sf2和.sfz格式的音色庫。本文將詳細介紹Polyphone的基礎操作及使用方法。 一、安裝和簡介 首先,我們需要下載並安裝…

    編程 2025-04-29
  • Python按位運算符和C語言

    本文將從多個方面詳細闡述Python按位運算符和C語言的相關內容,並給出相應的代碼示例。 一、概述 Python是一種動態的、面向對象的編程語言,其按位運算符是用於按位操作的運算符…

    編程 2025-04-29
  • Python語言由荷蘭人為中心的全能編程開發工程師

    Python語言是一種高級語言,很多編程開發工程師都喜歡使用Python語言進行開發。Python語言的創始人是荷蘭人Guido van Rossum,他在1989年聖誕節期間開始…

    編程 2025-04-28
  • Python語言設計基礎第2版PDF

    Python語言設計基礎第2版PDF是一本介紹Python編程語言的經典教材。本篇文章將從多個方面對該教材進行詳細的闡述和介紹。 一、基礎知識 本教材中介紹了Python編程語言的…

    編程 2025-04-28

發表回復

登錄後才能評論