system與execl

system()與execl()可以執行bash指令,把bash指令作為參數傳給system()與execl()函式。

include

#include <unistd.h> 

system

語法

int system(const char *command)

參數 bash指令

傳回值

  • 0:成功
  • 非0: 可能失敗

不管傳回值是0與非0,都不會修改全域變數errno,所以使用strerror()或perror()都會傳回Success

傳回值0程式碼

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <unistd.h>  // system() head file
#include <cstring>   // strerror() 需要head file
#include <cerrno>    // errno全域變數的head file
using namespace std;
int main() {
  int ret = system("/bin/ls -l");
  cout << "ret = " << ret << endl;
  cout << errno << ":" << strerror(errno) << endl;
  return 0;
}
-rwxrwxr-x 1 cici cici  16688 12月 13 13:32 system_test
-rw-rw-r-- 1 cici cici    333 12月 13 13:32 system_test.cpp
ret = 0
0:Success

傳回值非0程式碼1

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <unistd.h>  // system() head file
#include <cstring>   // strerror() 需要head file
#include <cerrno>    // errno全域變數的head file
using namespace std;
int main() {
  int ret = system("/bin/laaaaa -l");
  cout << "ret = " << ret << endl;
  cout << errno << ":" << strerror(errno) << endl;
  return 0;
}
sh: 1: /bin/laaaaa: not found
ret = 32512
0:Success

傳回值非0程式碼2

若bash是執行其它程式碼,其它程式碼的return值非0,system()函式的傳回值也會是非0。

以下是被呼叫的程序system_call.cpp

1
2
3
4
5
6
#include <iostream>
using namespace std;
int main() {
  cout << "被呼叫的程序: system_call" << endl;
  return 12;
} 

system_test.cpp

1
2
3
4
5
6
7
int main() {
  // 執行system_call
  int ret = system("/home/cici/test/app/system_call");
  cout << "ret = " << ret << endl;
  cout << errno << ":" << strerror(errno) << endl;
  return 0;
}
被呼叫的程序: system_call
ret = 3072
0:Success

可以看出ret傳回值為非0,errno也是0,代表Success

execl

語法

int execl(const char *path, const char *arg, ..., nullptr);

使用範例1

1
int ret = execl("/home/cici/system_call", "/home/cici/system_call", nullptr);

前2個參數都是執行檔案路徑,都是相同,最後一個參數為nullptr,代表之後沒有參數了。

使用範例2

1
2
// 呼叫/bin/ls -l /tmp
int ret = execl("/bin/ls", "/bin/ls", "-l", "/tmp", nullptr);

前2個參數都是bash指令執行檔路徑,都是相同,之後為bash指令的參數,最後一個參數為nullptr,代表之後沒有參數了。

程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <unistd.h>  // exec() head file
#include <string.h>
#include <cstring>   // strerror() 需要head file
#include <cerrno>    // errno全域變數的head file
using namespace std;
int main() {
  // 執行execl
  int ret = execl("/home/cici/test/app/system_call", "/home/cici/test/app/system_call", nullptr);
  cout << "ret = " << ret << endl;
  cout << errno << ":" << strerror(errno) << endl;
  return 0;
}
被呼叫的程序: system_call

從以上的執行結果可以發現,不會執行以下二行,因為程序已經被system_call程式碼取代

1
2
  cout << "ret = " << ret << endl;
  cout << errno << ":" << strerror(errno) << endl;

execl 函數用於在目前的 process 中啟動一個新的程式,取代目前 process 的執行。

也就是成功執行後,原來的程式碼將不再執行,因為目前 process 已被新程式取代。

如果要繼續執行原本的程式,可以使用 fork 讓 execl 在 child process 中執行

使用ps -ef | grep execl,會發現從頭到尾只有一個pid

但若是執行的是system(),會發現有2個pid

以下二個程式碼增加getpid()

execl_test.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <unistd.h>  // exec() head file
#include <string.h>
#include <cstring>   // strerror() 需要head file
#include <cerrno>    // errno全域變數的head file
using namespace std;
int main() {
  cout << "execl_test pid = " << getpid() << endl;
  // 執行execl
  int ret = execl("/home/cici/test/app/system_call", "/home/cici/test/app/system_call", nullptr);
  cout << "ret = " << ret << endl;
  cout << errno << ":" << strerror(errno) << endl;
  return 0;
}

system_call.cpp

1
2
3
4
5
6
7
8
#include <iostream>
#include <unistd.h>  // getpid() head file
using namespace std;
int main() {
  cout << "system_call pid = " << getpid() << endl;
  cout << "被呼叫的程序: system_call" << endl;
  return 12;
}

編譯二個檔案,並執行execl_test

由執行結果可以發現,二個執行檔的pid都一模一樣。

execl_test pid = 131087
system_call pid = 131087
被呼叫的程序: system_call

fork與execl

為了解決execl會取代主程序,使用fork()建立子程序,由子程序被execl取代,就不會取代主程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <unistd.h>
#include <string.h>
#include <cstring>   // strerror() 需要head file
#include <cerrno>    // errno全域變數的head file
using namespace std;
int main() {
  // fork傳回值pid
  pid_t pid = fork();
  if (pid > 0) {
    // 父程序
    for (int i = 0; i < 15; i++) {
      sleep(1);
      cout << "第" << i << "秒" << endl;
    }
  } else {
    int ret = execl("/home/cici/test/app/system_call", "/home/cici/test/app/system_call", nullptr);
    cout << "ret = " << ret << endl;
    cout << errno << ":" << strerror(errno) << endl;
  }
  cout << "結束" << endl;
}
system_call pid = 146493
被呼叫的程序: system_call
第0秒
第1秒
第2秒
第3秒
第4秒
第5秒
第6秒
第7秒
第8秒
第9秒
第10秒
第11秒
第12秒
第13秒
第14秒
結束

results matching ""

    No results matching ""