2012-04-03 38 views
8

Ở đây tôi đã viết một chương trình C thực thi hi.sh tệp bằng cách sử dụng cuộc gọi system. Ở đây tôi sử dụng . ./hi.sh vì vậy tôi muốn thực thi kịch bản này trong cùng một vỏ và sau đó cố gắng để có được biến môi trường bằng cách sử dụng chức năng getenv, nhưng ở đây tôi nhận được đầu ra khác nhau từ những gì tôi mong đợi.Lấy các biến môi trường sử dụng mã C

File hi.sh chứa

export TEST=10 
return 

Có nghĩa là khi tôi chạy hi.sh tập tin này bằng cuộc gọi hệ thống, nó export TEST đặt giá trị đến 10 trong cùng một vỏ. Sau này, tôi đang cố gắng để có được giá trị này biến nhưng giá trị NULL nhất định của nó.

Và nếu tôi chạy tập lệnh này theo cách thủ công từ bảng điều khiển như . ./hi.sh thì nó hoạt động tốt và tôi nhận được 10 giá trị TEST sử dụng chức năng getenv("TEST").

Code:

#include <stdio.h> 
int main() 
{ 
    system(". ./hi.sh"); 
    char *errcode; 
    char *env = "TEST"; 
    int errCode;  
    errcode = getenv(env); 
    printf("Value is = %s\n",errcode); 
    if (errcode != NULL) { 
     errCode =atoi(errcode); 
     printf("Value is = %d\n",errCode); 
    } 
} 

đầu ra:

Value is = (null) 

Làm thế nào tôi có thể xuất khẩu biến THI trong vỏ chương trình? Nếu system() thực hiện các lệnh trong trình bao khác nhau thì làm cách nào tôi có thể sử dụng mã chương trình C để nhận biến môi trường được xuất bởi trình vỏ được gọi thông qua lệnh gọi system()?

Trả lời

7

Như thường lệ, trang người đàn ông giải thích điều này, nhưng bạn cần phải đọc nó rất cẩn thận.

DESCRIPTION 
     system() executes a command specified in command by calling /bin/sh -c 
     command, and returns after the command has been completed. During exe‐ 
     cution of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT 
     will be ignored. 

Nói cách khác, system() đầu tiên bắt đầu/bin/sh và sau đó có/bin/sh bắt đầu bất kỳ lệnh nào bạn muốn thực thi. Vì vậy, những gì xảy ra ở đây là biến TEST được xuất khẩu vào/bin/sh shell hệ thống() gọi ngầm bắt đầu, nhưng không phải chương trình được gọi là system().

+0

Vậy làm cách nào tôi có thể đạt được mục tiêu này? – user1089679

+0

Làm cách nào để xuất biến TEST thành chương trình Shell? – user1089679

+2

@ user1089679 Nguồn tập lệnh của bạn (thiết lập môi trường) trước khi chạy chương trình C. Đó là cách các biến môi trường được thiết kế để sử dụng. –

0

Bạn có thể thiết lập các biến môi trường trong quá trình của riêng bạn sử dụng setenv() (mà system() sau đó âm thầm đi vào tiến trình con, hoặc một cách rõ ràng vượt qua các biến bằng cách sử dụng fork()execve() để chạy shell script.

+0

cảm ơn bạn đã trả lời. Nhưng tôi phải gọi shell script bằng cách sử dụng gọi hệ thống và nó cần thiết để thiết lập các biến môi trường từ script. Sau này tôi muốn lấy biến môi trường từ shell – user1089679

+2

Điều đó là không thể. Các biến chỉ có thể được truyền cho các tiến trình mới được tạo, không phải quay lại tiến trình cha. Kịch bản lệnh của bạn sẽ tạo ra một số đầu ra, mà bạn có thể lấy bằng cách sử dụng 'popen()' thay vì 'system()'. –

9

Đứa trẻ quá trình không thể trực tiếp thiết lập môi trường quá trình cha mẹ. cách tiếp cận sử dụng system()getenv() là cam chịu thất bại, do đó.

Nếu bạn đang cố gắng để nhập khẩu các biến được lựa chọn theo quy định của kịch bản hi.sh, sau đó bạn có một vài lựa chọn. Hoặc bạn có thể đọc tập lệnh hi.sh và tìm ra những gì nó sẽ đặt chúng thành (khá khó), hoặc bạn có thể chạy tập lệnh và có mã bạn chạy báo cáo lại trên các biến môi trường quan tâm.

Giả sử rằng hi.sh đặt $ENV1$ENV2. Bạn có thể sử dụng popen() để lấy lại giá trị cho chương trình của mình và setenv() để đặt môi trường của chương trình.Tóm tắt:

FILE *fp = popen(". ./hi.sh; echo ENV1=$ENV1; echo ENV2=$ENV2", "r"); 

while (fgets(buffer, sizeof(buffer), fp) != 0) 
{ 
    ...split the buffer into env_name, env_value... 
    setenv(env_name, env_value); 
} 

pclose(fp); 

Lưu ý rằng tôi đã bao gồm tên biến trong thông tin được lặp lại; điều này đơn giản hóa cuộc sống. Nếu danh sách các biến của bạn trở nên khó sử dụng, có thể bạn chạy ". ./hi.sh; env" để có được toàn bộ môi trường, sau đó đọc từng dòng và làm việc từ danh sách được tích hợp của bạn cho dù đó là cài đặt biến mà bạn muốn sử dụng hay không. Hoặc bạn có thể chỉ cần thiết lập toàn bộ môi trường của bạn một lần nữa, nếu điều đó vui lòng bạn. Bạn nên kiểm tra xem hàm setenv() có thành công không (nó trả về 0 khi nó thành công). Bạn cũng nên kiểm tra xem popen() có thành công hay không (fp != 0). Trong ngữ cảnh này, bạn có thể sử dụng strtok() để tìm kiếm số = tách tên biến khỏi giá trị; nó chà đạp một byte null trên =, tạo cho bạn một null chấm dứt tên và một giá trị null chấm dứt:

char *env_name = strtok(buffer, "="); 
    char *env_value = buffer + strlen(env_name) + 1; 
    if (setenv(env_name, env_value) != 0) 
     ...report trouble... 
1

Một giải pháp khả thi là phải có chương trình của bạn exec chính nó thông qua vỏ khác. Shell đó thay thế chương trình đang chạy, sau đó đọc các biến môi trường và sau đó thay thế shell bằng một bản sao mới của chương trình. Bạn cần phải cho biết bản sao mới rằng nó đã thực hiện một exec hoặc nó sẽ chỉ lặp đi lặp lại làm nó hơn và hơn. Bạn có thể tìm biến môi trường hoặc truyền cờ dòng lệnh.

Một ví dụ chưa được kiểm tra:

execl("/bin/sh", "-c", ". ./hi.sh; exec ./a.out --envset", NULL); 

Bạn sẽ cần phải thay thế a.out với bất cứ tên chương trình thực sự là. Bạn có thể muốn trích xuất nó từ argv [0] và cũng vượt qua phần còn lại của mảng argv. Nhưng bạn phải định dạng lại các đối số để làm đối số trình bao, vì vậy chúng cần được trích dẫn khi cần thiết, v.v.

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