2009-11-08 57 views

Trả lời

17

Chức năng exec thay thế hình ảnh tiến trình đang chạy khi thành công, không có con nào được tạo (trừ khi bạn tự làm điều đó trước đây với fork()). Hàm system() làm ngã ba một tiến trình con và trả về khi lệnh được cung cấp kết thúc thực thi hoặc một lỗi xảy ra.

78

system() gọi tới sh để xử lý dòng lệnh của bạn, để bạn có thể mở rộng ký tự đại diện, v.v. exec() và bạn bè của nó thay thế hình ảnh quy trình hiện tại bằng một hình ảnh quy trình mới.

Với system(), chương trình của bạn tiếp tục chạy và bạn lấy lại một số trạng thái về lệnh bên ngoài mà bạn đã gọi. Với exec(), quá trình của bạn bị xóa.

Nói chung, tôi đoán bạn có thể nghĩ là system() là giao diện cấp cao hơn. Bạn có thể tự sao chép chức năng của nó bằng cách sử dụng một số kết hợp fork(), exec()wait().

Để trả lời câu hỏi cuối cùng của bạn, system() gây ra quá trình tạo con và gia đình exec() thì không. Bạn sẽ cần phải sử dụng fork() cho điều đó.

+0

làm 'cái gọi system' spawns một vỏ mới cũng để thực hiện lệnh nhất định hoặc nó thực thi các lệnh trong cùng một vỏ . –

+0

@Krishna_Oza - không có "cùng một trình bao", trừ khi chương trình gọi 'hệ thống()' là chính nó là một trình bao. Tôi không chắc chắn tôi làm theo. Tài liệu của tôi ở đây nói: "Hàm' system() 'đưa lệnh đối số cho trình thông dịch lệnh' sh (1) '." –

+0

Trích dẫn từ ['system' POSIX manual] (http://man7.org/linux/man-pages/man3/system.3p.html): * Hàm' system() 'sẽ hoạt động như thể một tiến trình con là được tạo ra bằng cách sử dụng ['fork()'] (http://man7.org/linux/man-pages/man3/fork.3p.html), và tiến trình con đã gọi ra tiện ích sh bằng cách sử dụng ['execl()'] (http://man7.org/linux/man-pages/man3/exec.3p.html) như sau: 'execl (," sh "," -c ", lệnh, (char *) 0);' * . –

6

system() sẽ thực thi lệnh được cung cấp trong quá trình con mà nó sinh ra. exec() sẽ thay thế quy trình hiện tại bằng cách gọi trình thực thi mới mà bạn chỉ định. Nếu bạn muốn sinh ra một quá trình con bằng cách sử dụng exec, bạn sẽ phải fork() quá trình của bạn trước.

2

Hệ thống() sẽ gọi trình bao lệnh mặc định của hệ thống, sẽ thực thi chuỗi lệnh được truyền dưới dạng đối số, chính nó có thể hoặc không thể tạo thêm quy trình, phụ thuộc vào lệnh và hệ thống. Dù bằng cách nào, ít nhất một quá trình trình bao sẽ được tạo ra.

Với hệ thống() bạn có thể gọi bất kỳ lệnh nào, trong khi với lệnh exec(), bạn chỉ có thể gọi một tệp thi hành. Shell script và batch file phải được thực hiện bởi shell lệnh.

Về cơ bản, chúng hoàn toàn khác nhau được sử dụng cho các mục đích khác nhau. Hơn nữa exec() thay thế quá trình gọi và không trả lại. Một so sánh hữu ích hơn sẽ là giữa system() và spawn(). Trong khi hệ thống có thể đơn giản hơn để gọi, nó trả về một giá trị cho bạn biết liệu trình bao lệnh có được gọi hay không, và không cho bạn biết gì về sự thành công của lệnh đó. Với spawn() bạn có thể lấy mã thoát của quy trình; theo quy ước khác không được sử dụng để chỉ ra các điều kiện lỗi. Giống như exec() spawn() phải gọi một tập tin thực thi, không phải là một kịch bản lệnh shell hoặc lệnh dựng sẵn.

5

Để tạo một quá trình:

  • fork(2), một cuộc gọi hệ thống trực tiếp đến kernel

Để thực hiện một chương trình, thay thế hình ảnh hiện tại:

  • execve(2), một hệ thống gọi trực tiếp đến hạt nhân, thông thường ly vừa gọi exec

Để chờ một quá trình con để kết thúc:

  • wait(2), một cuộc gọi hệ thống trực tiếp đến kernel

Để chạy một chương trình trong một vỏ trong một quy trình con và chờ cho đến khi hoàn thành:

  • system(3), một chức năng thư viện

Để có được man pages cho tất cả những điều trên:

$ man 2 fork execve wait 
    $ man 3 system 
1

exec() thay thế quá trình hoạt động hiện nay với hình ảnh quá trình chức năng được thực hiện ..các tập tin thực thi chỉ có thể được gọi bằng cách sử dụng này.

hệ thống() tắt một quy trình mới ngầm để phục vụ yêu cầu và trả về giá trị mà nó thu được thông qua quá trình con nó được chia rẽ ban đầu. Nó sử dụng vỏ mặc định của hệ thống để thực hiện thao tác.

0

Hệ thống() sẽ tạo quy trình con và gọi một trình bao con khác trong khi exec() sẽ không tạo tiến trình con.Given Ví dụ sẽ xóa sự khác biệt.

một số mã ...

exec ('ls -l')

echo "1 2 3" // Điều này sẽ không được thực hiện trong bash (như exec lệnh sử dụng cùng một vỏ)

một số mã ...

hệ thống (ls -l) echo "1 2 3" // Điều này sẽ được thực thi sau khi hoàn thành quá trình hệ thống con vì chúng khác với cha mẹ PID.

0

Hệ thống() gọi chương trình mong muốn hoặc lệnh tích hợp bằng cách sử dụng trình bao, đây là một cách không hiệu quả vì trình bao được bắt đầu trước khi chương trình được bắt đầu.

Trong trường hợp họ thực hiện cuộc gọi hệ thống, toàn bộ hình ảnh mới đang được tạo, nghĩa là chúng thay thế quy trình hiện tại bằng quy trình mới được chỉ định bởi đường dẫn hoặc tệp hoặc bất kỳ đối số nào bạn đang đề cập.

Điều cần lưu ý là khi gia đình exec của cuộc gọi hệ thống được sử dụng, chương trình gốc sẽ không còn chạy sau khi chương trình mới bắt đầu.

0

Có một số khác biệt đáng kể giữa exec(2)system(3) cần lưu ý. system() trả về người gọi, trong khi exec() thay thế mã hiện tại bằng hình ảnh mới. Điều này đã được giải thích ở trên.

Tuy nhiên, sự khác biệt không quá tinh tế đến khi bạn muốn chạy thủ tục và sau đó quay lại mã hiện có của bạn, nhận mã trả về từ thủ tục được gọi. system() không cung cấp mã trả về, nhưng mã trả về chỉ có thể được sử dụng để phát hiện tình trạng lỗi và không thể sử dụng để khôi phục mã trả lại.

Một chuỗi thích hợp có thể có của các cuộc gọi hệ thống là:

#include <unistd.h> 
#include <sys/wait.h> 
#define NUMARGS 2 

int main (int argc, char *argv[]) 
{ 
    pid_t child_pid, wait_pid; 
    int * child_status; 
    char * exec_path = "/path/to/executable"; 
    char * child_args[NUMARGS] = {0,0}; 

    child_pid = fork(); 
    if (0 == child_pid) 
    { // In child process 
    ... 
    int child_ret_code = execv(exec_path, child_args); //or whichever flavor of exec() that floats your boat 
    ... // if child_ret_code = -1, process execv() error return 
    } 
    else if (-1 == child_pid) 
    { 
    ... //process error return from fork 
    } 
    else if (0 < child_pid) 
    { // Parent process 
    wait_pid = wait(child_status); 
    if (-1 == wait_pid) 
    { 
     ... //Process error return from wait() 
    } 
    else 
    { // Good fork/exec/wait 
     if (WIFEXITED(child_status)) // Child exited normally and hopefully returned exit code 
     { 
      int child_ret_code = WEXITSTATUS(child_status); 
      ... // Continue on as you would after call to system(3) 
       // except now you have the return code you needed 
     } 
    } 
    } 
} 

Có tinh tế khác để chuỗi này có thể được xác định bởi một đọc cẩn thận của các trang người đàn ông có liên quan, nhưng mã này sẽ làm việc tốt trong sự vắng mặt Ngoài ra, các khai báo nội tuyến có thể giới hạn phạm vi của các biến, nhưng được bao gồm để cho phép mã này được sử dụng như một khuôn mẫu hoạt động (bạn có thể sử dụng một kiểu mã hóa khác :-).

0

Nói chung, "hệ thống" rất kém hiệu quả và bạn không nên sử dụng nó trừ khi bạn có một mã nhỏ. Nếu bạn cần thực hiện một số chương trình trong quá trình của mình, bạn nên sử dụng lệnh fork & mặc dù bạn làm cho nó phức tạp hơn. Dưới đây là danh sách các khác biệt giữa chúng:

1- lệnh "hệ thống" tạo bản sao trình bao để thực thi chương trình của bạn. Mỗi khi bạn gọi một hệ thống, bạn tạo một bản sao của vỏ. Vì vậy, không sử dụng nó khi bạn có rất nhiều chương trình để thực hiện bên trong quá trình của bạn. 2- Cụ thể, nếu bạn muốn thực hiện các chức năng hệ thống như "mv", "mkdir", tốt hơn nên sử dụng các thường trình như mkdir(), unlink() hoặc remove() thay vì thực thi chúng thông qua "system (" rm .... ") hoặc hệ thống (" mkdir .... ")".

3- Vì các cuộc gọi hệ thống sẽ thực thi chương trình bạn muốn, bạn có thể gặp một số vấn đề về quyền của người dùng. Ví dụ, ai đó có thể crack mã của bạn và thực hiện một cái gì đó khác thay vì chương trình bạn dự định thực hiện thông qua lệnh hệ thống.

Để biết thêm thông tin, bạn có thể đọc chương 11 của cuốn sách này: "Lập trình hệ thống UNIX" của David Curry.

0

Câu trả lời của JonSpencer là tốt, ngoại trừ child_status phải là int (không có con trỏ tới int) và phải được chuyển đến hàm chờ bằng cách tham chiếu.

Vì vậy, các mã sẽ là chủ yếu như nhau, chỉ cần thay đổi những vài điều:.

#include <unistd.h> 
#include <sys/wait.h> 
#define NUMARGS 2 

int main (int argc, char *argv[]) 
{ 
    pid_t child_pid, wait_pid; 
    int child_status; 
    char * exec_path = "/path/to/executable"; 
    char * child_args[NUMARGS] = {0,0}; 

    child_pid = fork(); 
    if (0 == child_pid) 
    { // In child process 
    ... 
    int child_ret_code = execv(exec_path, child_args); //or whichever flavor of exec() that floats your boat 
    ... // if child_ret_code = -1, process execv() error return 
    } 
    else if (-1 == child_pid) 
    { 
    ... //process error return from fork 
    } 
    else if (0 < child_pid) 
    { // Parent process 
    wait_pid = wait(&child_status); 
    if (-1 == wait_pid) 
    { 
     ... //Process error return from wait() 
    } 
    else 
    { // Good fork/exec/wait 
     if (WIFEXITED(child_status)) // Child exited normally and hopefully returned exit code 
     { 
      int child_ret_code = WEXITSTATUS(child_status); 
      ... // Continue on as you would after call to system(3) 
       // except now you have the return code you needed 
     } 
    } 
    } 
} 

(Chỉ ra rằng tôi không có đủ uy tín chưa bình luận bài của Jon vì vậy tôi sửa nó Một số mọi người từ chối phiên bản yêu cầu tôi trả lời câu hỏi thay vì chỉnh sửa nó, nhưng tôi nghĩ rằng trong trường hợp này đơn giản hơn, thực tế và rõ ràng hơn để chỉnh sửa mã hiện có chỉ sửa một lỗi nhỏ hơn là viết toàn bộ/dán/sửa đổi answer.) Dù sao, nhờ JonSpencer cho câu trả lời của bạn, nó thực sự hữu ích cho tôi!

1

int system(const char *cmdstring); 

Ex: system("date > file");


Nhìn chung, hệ thống được thực hiện bằng cách gọi ngã ba, exec, và waitpid, có ba loại giá trị trả về.

  • Nếu một ngã ba bị lỗi hoặc waitpid trả về lỗi khác với EINTR, hệ thống trả về -1 với sai số đặt để cho biết lỗi.
  • Nếu exec không thành công, ngụ ý rằng hệ vỏ không thể được thực hiện, giá trị trả về là như thể shell đã thực thi exit (127).
  • Nếu không, tất cả ba hàm — fork, exec và waitpid — thành công và giá trị trả về từ hệ thống là trạng thái chấm dứt của shell, theo định dạng được chỉ định cho waitpid.

Các ngã ba chức năng là để tạo ra một quy trình mới (đứa trẻ) mà sau đó gây một chương trình khác được thực hiện bằng cách gọi một trong những exec chức năng. Khi một quá trình gọi một trong các hàm thực thi , quá trình đó sẽ được thay thế hoàn toàn bằng chương trình mới và chương trình mới bắt đầu thực hiện ở chức năng chính của nó. Quá trình ID không thay đổi trên một exec, bởi vì một quá trình mới không được tạo ra; exec chỉ thay thế quy trình hiện tại — văn bản, dữ liệu, đống và phân đoạn ngăn xếp — với chương trình hoàn toàn mới từ đĩa.

Có sáu chức năng exec khác nhau,


int execl(const char *pathname, const char *arg0, ... /* (char *)0 */); 

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

int execle(const char *pathname, const char *arg0, .../* (char *)0, char *const envp[] */); 

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

int execlp(const char *filename, const char *arg0,... /* (char *)0 */); 

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

Các vấn đề liên quan