Có bash hỗ trợ forking tương tự như ngã ba C ()?


25

Tôi có một tập lệnh mà tôi muốn rẽ nhánh tại một thời điểm để hai bản sao của cùng một tập lệnh đang chạy.

Ví dụ: tôi muốn tồn tại tập lệnh bash sau:

echo $$
do_fork()
echo $$

Nếu tập lệnh bash này thực sự tồn tại, đầu ra dự kiến ​​sẽ là:

<ProcessA PID>
<ProcessB PID>
<ProcessA PID>

hoặc là

<ProcessA PID>
<ProcessA PID>
<ProcessB PID>

Có cái gì đó mà tôi có thể đặt thay cho "do_fork ()" để có được loại đầu ra này hoặc để làm cho tập lệnh bash thực hiện một ngã ba giống như C không?

Câu trả lời:


23

Vâng. Forking được đánh vần &:

echo child & echo parent

Điều có thể khiến bạn bối rối đó $$không phải là PID của quy trình shell, đó là PID của quy trình shell ban đầu . Điểm quan trọng của cách làm này $$là một mã định danh duy nhất cho một trường hợp cụ thể của tập lệnh shell: nó không thay đổi trong quá trình thực thi tập lệnh và nó khác với $$bất kỳ tập lệnh đang chạy đồng thời nào khác. Một cách để có được PID thực tế của quá trình shell là sh -c 'echo $PPID'.

Luồng điều khiển trong shell không giống như C. Nếu trong C, bạn viết

first(); fork(); second(); third();

sau đó một vỏ tương đương là

after_fork () { second; third; }
first; after_fork & after_fork

Dạng vỏ đơn giản first; child & parenttương ứng với thành ngữ C thông thường

first(); if (fork()) parent(); else child();

&$$tồn tại và hành xử theo cách này trong mọi vỏ kiểu Bourne và trong (t) csh. $PPIDkhông tồn tại trong vỏ Bourne gốc nhưng nằm trong POSIX (vì vậy nó có trong tro, bash, ksh, zsh, khắc).


3
Nhưng về cơ bản đó là "fork + exec", không chỉ fork.
mattdm

@mattdm: Uh? &là ngã ba, không có người thực hiện liên quan. Fork + exec là khi bạn khởi chạy một lệnh bên ngoài.
Gilles 'SO- ngừng trở nên xấu xa'

@mattdm: Ah, tôi nghĩ tôi thấy Cory đang làm gì. Không có exec, nhưng hai ngôn ngữ có luồng điều khiển khác nhau.
Gilles 'SO- ngừng trở nên xấu xa'

1
@Gilles: Toán tử điều khiển bash &bắt đầu một lớp con trong đó lệnh đã cho được thực thi. Ngã ba + thực hiện. Bạn không thể đặt &mà không có lệnh trước để thực thi.
mattdm

5
Chà, nếu "Forking được đánh vần &" là một tuyên bố đúng, bạn có thể tự đặt &một dòng. Nhưng bạn không thể. Nó không có nghĩa là "ngã ba ở đây". Nó có nghĩa là "thực hiện lệnh trước trong nền trong một khung con".
mattdm

10

Vâng, nó được gọi là subshells . Mã shell trong ngoặc đơn được chạy dưới dạng một nhánh con (fork). Tuy nhiên, vỏ đầu tiên thường đợi trẻ hoàn thành. Bạn có thể làm cho nó không đồng bộ bằng cách sử dụng bộ &kết thúc. Xem nó trong hành động với một cái gì đó như thế này:

#!/bin/bash

(sleep 2; echo "subsh 1")&
echo "topsh"

$ bash subsh.sh


5
Các dấu ngoặc đơn tạo ra một subshell, nhưng đó là fork + chờ đợi. &là ngã ba một mình. Nếu bạn muốn thực hiện nhiều hơn một đường ống trong quy trình con, thì đủ để sử dụng niềng răng (thực hiện nhóm mà không tạo quy trình con):{ sleep 2; echo child; } &
Gilles 'SO- ngừng trở nên xấu xa'

6

Không có bash bản địa (hoặc, theo hiểu biết của tôi, bất kỳ cách * nix shell điển hình nào khác) để làm điều này. Có rất nhiều cách để sinh ra các quá trình rẽ nhánh làm một cái gì đó không đồng bộ, nhưng tôi không nghĩ có bất cứ điều gì tuân theo ngữ nghĩa chính xác của lệnh gọi hệ thống fork ().

Cách tiếp cận điển hình sẽ là để kịch bản cấp cao nhất của bạn sinh ra những người trợ giúp thực hiện công việc bạn muốn tách ra. Nếu bạn làm $0 $@ &hoặc bất cứ điều gì, bạn sẽ bắt đầu lại từ đầu và cần phải tìm ra điều đó bằng cách nào đó.

Tôi thực sự bắt đầu nghĩ ra một số cách thông minh trong đó người ta có thể làm điều đó ....

Nhưng , trước khi bộ não của tôi bị cuốn theo điều đó, tôi nghĩ một quy tắc khá hay là: nếu bạn đang cố gắng viết một cái gì đó bằng vỏ và nó chứa đầy những mánh khóe thông minh và bạn muốn có thêm các tính năng ngôn ngữ, đã đến lúc chuyển đổi đến một ngôn ngữ lập trình thực sự .


2
Mặc dù quan điểm của bạn được thực hiện tốt - cú pháp của bash rất khó và nó thiếu các cấu trúc dữ liệu và tính năng thanh lịch hơn của Perl hoặc Python, bash giống như thật trong miền của nó . Đó là một ngôn ngữ dành riêng cho tên miền và tôi sẽ tranh luận thậm chí tốt hơn (ngắn gọn hơn, đơn giản hơn) so với Python trong nhiều trường hợp. Bạn có thể quản trị một loạt các hệ thống và không biết Python không? Vâng. Bạn có thể làm điều đó và không biết một chút bash [lập trình]? Tôi sẽ không muốn thử. Sau 30 năm lập trình shell, tôi nói với bạn rằng nó giống như thật. Và vâng, tôi nói tiếng Python. Nhưng đừng nhầm lẫn các bạn trẻ.
Mike S

2
Điều đó nói rằng, về mặt kỹ thuật tôi thích câu trả lời này hơn. Để nói rằng "&" là câu trả lời cho câu hỏi của người dùng, "ngã ba tại một thời điểm để hai bản sao của cùng một tập lệnh đang chạy" làm tôi bối rối. Những gì "&" làm, theo hướng dẫn bash, là "... thực thi lệnh [đã cho] ở chế độ nền trong một khung con." Nó phải chấm dứt một lệnh và nó liên quan đến một ngã ba (về mặt kỹ thuật, trong Linux, một bản sao ()), nhưng tại thời điểm đó, hai bản sao của cùng một tập lệnh không chạy.
Mike S
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.