Trường hợp sử dụng / ví dụ thực tế cho hàm thực thi dựng sẵn của Bash


12

Hãy xem xét điều này từ tài liệu của hàm thực thi dựng sẵn của Bash:

exec thay thế shell mà không tạo ra một quy trình mới

Vui lòng cung cấp một trường hợp sử dụng / ví dụ thực tế. Tôi không hiểu làm thế nào điều này có ý nghĩa.

Tôi googled và thấy về I / O chuyển hướng . Bạn có thể giải thích nó tốt hơn?


Câu trả lời:


18

execthường được sử dụng trong các tập lệnh shell mà chủ yếu đóng vai trò là trình bao bọc để bắt đầu các tệp nhị phân khác. Ví dụ:

#!/bin/sh

if stuff;
    EXTRA_OPTIONS="-x -y -z"
else
    EXTRA_OPTIONS="-a foo"
fi

exec /usr/local/bin/the.real.binary $EXTRA_OPTIONS "$@"

để sau khi trình bao bọc kết thúc chạy, nhị phân "thực" sẽ tiếp quản và không còn bất kỳ dấu vết nào của tập lệnh trình bao tạm thời chiếm cùng một vị trí trong bảng quy trình. Nhị phân "thực" là một đứa con trực tiếp của bất cứ thứ gì đưa ra nó thay vì một đứa cháu.

Bạn cũng đề cập đến chuyển hướng I / O trong câu hỏi của bạn. Đó là một trường hợp sử dụng hoàn toàn khác execvà không liên quan gì đến việc thay thế vỏ bằng một quy trình khác. Khi execkhông có đối số, như vậy:

exec 3>>/tmp/logfile

sau đó các chuyển hướng I / O trên dòng lệnh có hiệu lực trong quy trình shell hiện tại, nhưng quá trình shell hiện tại tiếp tục chạy và chuyển sang lệnh tiếp theo trong tập lệnh.


1
Bạn có thể nói rằng hai trường hợp có liên quan đến cả hai, execnói với shell không thực hiện hành động (thực hiện lệnh hoặc thực hiện chuyển hướng) trong một quy trình con, nhưng trong cùng một quy trình.
Stéphane Chazelas

5

Tôi đã sử dụng một shell execdựng sẵn để nhận ID tiến trình (PID) cho chương trình Java. Có thể có một cách để có được PID từ bên trong Java bây giờ, nhưng vài năm trước, không có. Khi một tiến trình có PID riêng, nó có thể ghi nó ra tệp PID (tìm /var/run/tên tệp có hậu tố '.pid') để cho phép các chương trình quản lý biết PID của quy trình đang chạy và để ngăn chặn trường hợp thứ hai của cùng một máy chủ từ chạy. Nó hoạt động như thế này:

exec java -cp=YourServer.jar StartClass -p $$

Mã trong main()phương thức lớp StartClassxử lý phân tích cú pháp đối số và có thể tìm ID tiến trình riêng của nó.


2

Để giải trí, hãy chạy chương trình sau (được dịch sang ngôn ngữ thực hiện mà bạn chọn) trong nền trên hệ thống có quy trình và giới hạn quy trình người dùng.

while(true) fork();

Bây giờ, mọi vị trí trong bảng quy trình mà bạn được phép sử dụng đều có đầy đủ các bản sao của chương trình đang chạy đó, bạn dự định giết nó như thế nào? Việc khởi chạy kill (1) yêu cầu một khe xử lý khác mà bạn không thể có. Chắc chắn sẽ rất hữu ích khi lớp vỏ tự thay thế bằng lệnh kill ...

exec /bin/kill -9 -1

(Giả sử hệ thống của bạn đã giết (1) tại / bin / kill. "Exec` which kill` -9 -1 "có khả năng an toàn hơn.) Điều này sẽ gửi SIGKILL đến mọi quy trình bạn có thể.

(Lưu ý: Không đăng xuất khỏi trình khởi chạy của bạn trừ khi giới hạn quy trình luôn cho phép đăng nhập mới một vị trí quy trình cho trình bao của nó. Điều này có thể khó khăn hơn một chút để làm sạch nếu bạn làm. Tôi chắc chắn không làm điều này trong đầu thập niên 90. Không.)


3
(1) Câu trả lời này sẽ tốt hơn một chút nếu bạn thực sự chỉ ra execlệnh sẽ hữu ích trong tình huống này. (2) Câu trả lời này có phần cổ xưa; các killlệnh đã được một lệnh dựng sẵn trong bash trong nhiều năm, chủ yếu là do mối quan tâm này.
G-Man nói 'Phục hồi Monica'

@ G-Man: Bạn hiểu rằng mục của bạn (2) làm cho câu trả lời này trở thành phản hồi chính xác cho OP?
Tháp Eric

Không, tôi không hiểu điều đó. Xin vui lòng giải thích cho tôi.
G-Man nói 'Phục hồi Monica'

4
Tôi không theo dõi bạn. Câu hỏi không yêu cầu các ví dụ thực tế của tất cả các lệnh dựng sẵn bash; nó yêu cầu các ví dụ về exec- và thực tế killlà một nội dung không thực sự có liên quan đến execnội dung.
G-Man nói 'Phục hồi Monica'

1
Tôi chỉ đọc cập nhật của bạn để trả lời của bạn. (1) Đoán xem? Nếu bảng quy trình đã đầy, thì lệnh thay thế (ví dụ `which kill`:) sẽ không hoạt động. (2) BTW, $(…)hình thức được khuyến nghị trên `…`biểu mẫu. (3) Nhưng không có gì nguy hiểm khi đoán trong thư mục. Nếu bạn vô tình gõ exec /binn/kill, bạn sẽ chỉ nhận được một thông báo lỗi và vỏ của bạn sẽ không biến mất. (4) Nhưng bạn thậm chí không cần phải lo lắng về những gì thư mục killlà trong.  execSử dụng $PATH, giống như lệnh bình thường, vì vậy exec kill …các công trình (giả sử bạn có /bintrong con đường tìm kiếm của bạn).
G-Man nói 'Phục hồi Monica'

1
  • Điều này tương tự như ví dụ của Bruce về việc cần biết PID của một quá trình:

    (cmdpid = $ BASHPID; (ngủ 300; giết "$ cmdpid") & thực hiện lệnh chạy dài )

    trong đó bạn

    1. Bắt đầu một subshell (bên ngoài ()),
    2. Tìm hiểu các PID của subshell. ( $$sẽ cung cấp cho bạn PID của shell chính.)
    3. Tách một subshell giết chết tiến trình của bạn sau khi hết thời gian và
    4. Chạy một lệnh trong quá trình của lớp con mà bạn đã tạo ở bước 1.

    Điều này sẽ chạy long-running-command, nhưng chỉ trong một khoảng thời gian giới hạn, được xác định trước. 

  • Điều này là một chút phù phiếm, nhưng, nếu bạn quyết định rằng bạn muốn được root (hoặc một số người dùng khác) cho phần còn lại của phiên đăng nhập của bạn, bạn có thể exec su.

    Trên thực tế, tôi có thể tưởng tượng một kịch bản mà điều này sẽ thực sự hữu ích. Giả sử rằng bạn đã đăng nhập vào một hệ thống từ xa và, vì một số lý do, có vấn đề với việc ngắt kết nối và bắt đầu một kết nối mới. Ví dụ: giả sử hệ thống từ xa có tường lửa tuân theo lịch trình. Bạn được phép kết nối khi bạn đã làm và các kết nối được thiết lập không bị đóng, nhưng tại thời điểm hiện tại, các kết nối mới không được chấp nhận.

    Bạn đã thực hiện những gì bạn muốn làm và bạn đã sẵn sàng để đăng xuất. Bob bạn của bạn đang ở trong phòng với bạn và anh ấy muốn thực hiện một số công việc trên hệ thống từ xa - nhưng anh ấy sẽ không thể kết nối. Vì vậy, bạn gõ exec su - bobvà khi lời nhắc mật khẩu xuất hiện, hãy chuyển máy trạm sang cho anh ta. Hiện tại không có quy trình nào với UID của bạn (trừ khi bạn chạy một cái gì đó trong nền), vì vậy Bob sẽ không thể làm hỏng các tệp của bạn. Anh ấy sẽ có hiệu quả tiếp nhận kết nối của bạn (với sự đồng ý và hợp tác của bạn).

    Ghi chú:

    • Tất nhiên điều này sẽ không hoạt động nếu bạn không được phép chạy su.
    • Nó sẽ được ghi lại, vì vậy bạn có thể cần phải giải thích động cơ của bạn với ai đó. Vì bạn đang phá vỡ chính sách (lịch trình tường lửa), bạn có thể gặp rắc rối.
    • Tôi không đảm bảo rằng nó an toàn 100%. Ví dụ, whocó thể vẫn sẽ hiển thị tên của bạn. Có thể hình dung rằng một số chương trình (được viết xấu) sẽ sử dụng điều đó để nghĩ rằng Bob là bạn và cho anh ta quyền truy cập vào tài nguyên của bạn.
    • Nếu hệ thống thực hiện kiểm toán, hành động của Bob có thể được kiểm tra dưới tên của bạn.

Lưu ý rằng trong thực tế trong hầu hết các shell, (a;b)đã giống (a;exec b)như các shell tối ưu hóa ngã ba cho lệnh cuối cùng trong một lớp con. Các ngoại lệ duy nhất dường như bashmksh. Sử dụng execgiúp đảm bảo nó.
Stéphane Chazelas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.