Làm thế nào để đúng một cách chính xác, bắt đầu một ứng dụng từ vỏ


21

Tôi thấy thật khó để diễn đạt câu hỏi một cách chính xác nhưng tôi sẽ cố gắng hết sức. Tôi sử dụng dwmlàm trình quản lý cửa sổ mặc định của mình vàdmenulà trình khởi chạy ứng dụng của tôi. Tôi hầu như không sử dụng các ứng dụng GUI ngoài trình duyệt của mình. Hầu hết công việc của tôi được thực hiện trực tiếp từ dòng lệnh. Hơn nữa, tôi là một fan hâm mộ lớn của chủ nghĩa tối giản liên quan đến hệ điều hành, ứng dụng, vv Một trong những công cụ tôi chưa bao giờ loại bỏ là trình khởi chạy ứng dụng. Chủ yếu là vì tôi thiếu hiểu biết chính xác về cách các trình khởi chạy ứng dụng hoạt động / những gì chúng làm. Ngay cả tìm kiếm trên internet rộng lớn chỉ hiển thị giải thích mơ hồ. Những gì tôi muốn làm là loại bỏ ngay cả trình khởi chạy ứng dụng của mình bởi vì ngoài việc thực sự sinh ra ứng dụng, tôi hoàn toàn không sử dụng nó. Để làm điều này, tôi thực sự muốn biết cách "chính xác" khởi động các ứng dụng từ trình bao. Do đó, ý nghĩa của "chính xác" có thể được xấp xỉ bằng "giống như trình khởi chạy ứng dụng sẽ làm".

Tôi biết về các cách sau đây để sinh ra các quy trình từ vỏ:

  1. exec /path/to/Program thay thế shell bằng lệnh được chỉ định mà không tạo quy trình mới
  2. sh -c /path/to/Program khởi chạy quá trình phụ thuộc vỏ
  3. /path/to/Program khởi chạy quá trình phụ thuộc vỏ
  4. /path/to/Program 2>&1 & khởi động quá trình độc lập shell
  5. nohup /path/to/Program & khởi chạy quy trình độc lập shell và chuyển hướng đầu ra sang nohup.out

Cập nhật 1: Tôi có thể minh họa những gì ví dụ như dmenutái cấu trúc nó từ các cuộc gọi lặp đi lặp lại ps -efltrong các điều kiện khác nhau. Nó sinh ra một lớp vỏ mới /bin/bashvà là một đứa con của lớp vỏ này /path/to/Program. Chừng nào đứa trẻ còn ở đó bao lâu thì cái vỏ sẽ ở xung quanh. (Cách nó quản lý cái này nằm ngoài tôi ...) Ngược lại nếu bạn phát hành nohup /path/to/Program &từ shell /bin/bashthì chương trình sẽ trở thành con của shell này NHƯNG nếu bạn thoát khỏi shell này, cha mẹ của chương trình sẽ là quá trình cao nhất. Vì vậy, nếu quá trình đầu tiên là ví dụ /sbin/init verbosevà nó có PPID 1thì nó sẽ là cha mẹ của chương trình. Đây là những gì tôi đã cố gắng giải thích bằng biểu đồ: chromiumđã được khởi chạy qua dmenu, firefoxđược khởi chạy bằng exec firefox & exit:

systemd-+-acpid
        |-bash---chromium-+-chrome-sandbox---chromium-+-chrome-sandbox---nacl_helper
        |                 |                           `-chromium---5*[chromium-+-{Chrome_ChildIOT}]
        |                 |                                                    |-{Compositor}]
        |                 |                                                    |-{HTMLParserThrea}]
        |                 |                                                    |-{OptimizingCompi}]
        |                 |                                                    `-3*[{v8:SweeperThrea}]]
        |                 |-chromium
        |                 |-chromium-+-chromium
        |                 |          |-{Chrome_ChildIOT}
        |                 |          `-{Watchdog}
        |                 |-{AudioThread}
        |                 |-3*[{BrowserBlocking}]
        |                 |-{BrowserWatchdog}
        |                 |-5*[{CachePoolWorker}]
        |                 |-{Chrome_CacheThr}
        |                 |-{Chrome_DBThread}
        |                 |-{Chrome_FileThre}
        |                 |-{Chrome_FileUser}
        |                 |-{Chrome_HistoryT}
        |                 |-{Chrome_IOThread}
        |                 |-{Chrome_ProcessL}
        |                 |-{Chrome_SafeBrow}
        |                 |-{CrShutdownDetec}
        |                 |-{IndexedDB}
        |                 |-{LevelDBEnv}
        |                 |-{NSS SSL ThreadW}
        |                 |-{NetworkChangeNo}
        |                 |-2*[{Proxy resolver}]
        |                 |-{WorkerPool/1201}
        |                 |-{WorkerPool/2059}
        |                 |-{WorkerPool/2579}
        |                 |-{WorkerPool/2590}
        |                 |-{WorkerPool/2592}
        |                 |-{WorkerPool/2608}
        |                 |-{WorkerPool/2973}
        |                 |-{WorkerPool/2974}
        |                 |-{chromium}
        |                 |-{extension_crash}
        |                 |-{gpu-process_cra}
        |                 |-{handle-watcher-}
        |                 |-{inotify_reader}
        |                 |-{ppapi_crash_upl}
        |                 `-{renderer_crash_}
        |-2*[dbus-daemon]
        |-dbus-launch
        |-dhcpcd
        |-firefox-+-4*[{Analysis Helper}]
        |         |-{Cache I/O}
        |         |-{Cache2 I/O}
        |         |-{Cert Verify}
        |         |-3*[{DOM Worker}]
        |         |-{Gecko_IOThread}
        |         |-{HTML5 Parser}
        |         |-{Hang Monitor}
        |         |-{Image Scaler}
        |         |-{JS GC Helper}
        |         |-{JS Watchdog}
        |         |-{Proxy R~olution}
        |         |-{Socket Thread}
        |         |-{Timer}
        |         |-{URL Classifier}
        |         |-{gmain}
        |         |-{localStorage DB}
        |         |-{mozStorage #1}
        |         |-{mozStorage #2}
        |         |-{mozStorage #3}
        |         |-{mozStorage #4}
        |         `-{mozStorage #5}
        |-gpg-agent
        |-login---bash---startx---xinit-+-Xorg.bin-+-xf86-video-inte
        |                               |          `-{Xorg.bin}
        |                               `-dwm-+-dwmstatus
        |                                     `-xterm---bash-+-bash
        |                                                    `-pstree
        |-systemd---(sd-pam)
        |-systemd-journal
        |-systemd-logind
        |-systemd-udevd
        |-wpa_actiond
        `-wpa_supplicant

Cập nhật 2: Tôi đoán câu hỏi cũng có thể được rút gọn thành: Phụ huynh của một quá trình nên làm gì? Nó có nên là một cái vỏ hay nó phải là initquá trình tức là quá trình với PID 1?


3
Câu trả lời ngắn gọn cho câu hỏi của bạn sẽ là "bất cứ điều gì đạt được kết quả bạn muốn."
Wayne Werner

1
dang, rác - bạn hỏi một số câu hỏi hay. nhưng tôi nghĩ rằng wayne trên mũi ở đây - bản chỉnh sửa mới nhất của bạn hỏi về init- câu trả lời có thể là ... có thể? nó phụ thuộc vào cách / nếu bạn dự định nói chuyện với nó, những gì initbạn sử dụng và nơi các kênh dữ liệu. Nói chung, công cụ đó sẽ có xu hướng tự giải quyết - đó là những gì initdành cho. Trong mọi trường hợp, thường là khi bạn trình bày một quy trình sau đó init. Hoặc nếu bạn muốn kiểm soát công việc, vỏ hiện tại.
mikeerv

Hahaha, chúc mừng @mikeerv; 4:37 sáng vào buổi sáng ở đây và là tiếng cười đầu tiên trong ngày. Đúng, những thứ đó luôn luôn làm việc ra. Tôi sẽ loại bỏ dmenuvà xem làm thế nào tôi hòa hợp với những gì tôi đã học. Tôi tìm thấy exec /path/to/Program & exithoặc /bin/bash -c /path/to/Program & exitlà khá có thể sử dụng. Nhưng tất cả họ làm1 tức là initphụ huynh của Programđó là tốt với tôi chừng này có ý nghĩa và không vi phạm bất kỳ cơ bản *nixnguyên tắc này.
lord.garbage

@ lord.garbage - exec &Tôi nghĩ vậy. Tôi thường chỉ làm công việc của mình từ thiết bị đầu cuối ... có lẽ bạn sẽ sử dụng được câu hỏi của ben crowell ở đây . Tôi có một câu trả lời ở đó, nhưng tất cả chúng đều rất tốt. dù sao đi nữa, khi bạn làm nền cho một quá trình và cha mẹ của nó chết như sau: sh -c 'cat & kill $$'bạn mồ côi nó, và cuối cùng nó sẽ được gặt hái. đó là công việc của init - đó là lý do tại sao tất cả họ đều rơi vào nó.
mikeerv

Có lẽ một câu hỏi đơn giản hơn bây giờ là: Làm thế nào có thể lấy cây quy trình trên từ vỏ : systemd--bash--chromium. Tất cả các phương pháp tôi thử cuối cùng sẽ dẫn đến một cây quy trình có dạng sau systemd--chromiumkhi tôi sinh ra firefox từ vỏ. Làm thế nào là vỏ quỷ ở đây? Nó không liên quan đến bất kỳ thiết bị đầu cuối.
lord.garbage

Câu trả lời:


7

Vâng, bạn dường như có một sự hiểu biết khá tốt về nó. Để làm rõ một số thứ bạn có,

  • sh -c /path/to/Program khá giống với

    $  Sh 
    % / path / to / Program 
    % Ctrl+ D                             (hoặc bạn có thể gõ “ lối ra ”) 
    $

    nơi bạn bắt đầu một tiến trình shell mới, cung cấp đường dẫn lệnh ứng dụng đến shell mới và sau đó để shell mới kết thúc. Tôi đã chỉ ra trình bao mới đưa ra một dấu nhắc khác cho mục đích minh họa; điều này có lẽ sẽ không xảy ra trong cuộc sống thực. Cấu trúc này hầu như hữu ích để thực hiện các công cụ phức tạp, như gói nhiều lệnh thành một gói, vì vậy chúng trông giống như một lệnh đơn (loại tập lệnh không tên sử dụng một lần) hoặc xây dựng các lệnh phức tạp, có thể từ các biến shell. Bạn hầu như không bao giờ sử dụng nó chỉ để chạy một chương trình duy nhất với (các) đối số đơn giản.sh -c "command"

  • 2>&1có nghĩa là chuyển hướng lỗi tiêu chuẩn sang đầu ra tiêu chuẩn. Điều này thực sự không có nhiều liên quan &; thay vào đó, bạn sử dụng nó khi một lệnh gửi thông báo lỗi đến màn hình ngay cả khi bạn nói và bạn muốn chụp các thông báo lỗi trong tệp.command > file
  • Chuyển hướng đầu ra thành nohup.outmột tác dụng phụ tầm thường của nohup. Mục đích chính của nó là chạy không đồng bộ (thường được gọi là trong nền tảng, hoặc là một quy trình độc lập của vỏ shell, để sử dụng các từ của bạn) và cấu hình nó để có cơ hội tiếp tục chạy tốt hơn nếu bạn có thể tiếp tục chạy nếu bạn chấm dứt shell (ví dụ, đăng xuất) trong khi lệnh vẫn đang chạy.nohup command &command

bash(1)Tài liệu tham khảo Bash là những nguồn thông tin tốt.


7

Có một vài cách để thực hiện một chương trình và tách nó ra khỏi một thiết bị đầu cuối. Một là chạy nó trong nền của một lớp con , như thế này (thay thếfirefox bằng chương trình yêu thích của bạn):

(firefox &)

Một cách khác là từ chối quá trình:

firefox & disown firefox

Nếu bạn tò mò về cách các trình khởi chạy ứng dụng hoạt động, hãy dmenucung cấp 1 tập lệnh nhị phân và 2 shell:dmenu , dmenu_pathdmenu_run, tương ứng.

dmenu_rundẫn đầu ra của dmenu_pathdmenu, từ đó biến các ống thành bất kỳ $SHELLbiến nào của bạn được đặt thành. Nếu nó trống, nó sẽ sử dụng /bin/sh.

#!/bin/sh
dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &

dmenu_pathphức tạp hơn một chút, nhưng tóm lại, nó cung cấp một danh sách các nhị phân trong $PATHbiến môi trường của bạn và sử dụng bộ đệm nếu có thể.

#!/bin/sh
cachedir=${XDG_CACHE_HOME:-"$HOME/.cache"}
if [ -d "$cachedir" ]; then
        cache=$cachedir/dmenu_run
else
        cache=$HOME/.dmenu_cache # if no xdg dir, fall back to dotfile in ~
fi
IFS=:
if stest -dqr -n "$cache" $PATH; then
        stest -flx $PATH | sort -u | tee "$cache"
else
        cat "$cache"
fi

Không cần thiết phải có chương trình chạy trong shell. Một cách khác để viết dmenu_run, mà không cần đường ống vào một vỏ sẽ là:

#!/bin/sh
$(dmenu_path | dmenu "$@") &

6

Tôi thích câu trả lời của G-Man rất nhiều. Nhưng tôi đang trả lời vì tôi nghĩ bạn đang lo lắng. Như Wayne chỉ ra, câu trả lời tốt nhất là "bất cứ điều gì đạt được kết quả bạn muốn".

Trong quản lý quy trình Unix, mọi quy trình đều có cha mẹ. Một ngoại lệ cho điều này làinit quá trình được khởi động bởi HĐH khi khởi động. Đó là hành vi bình thường đối với một quy trình cha mẹ để thực hiện tất cả các quy trình con của nó với nó khi nó chết. Điều này được thực hiện bằng cách gửi tín hiệu SIGHUP đến tất cả các tiến trình con; việc xử lý mặc định của SIGHUP chấm dứt quá trình.

Vỏ sinh sản của các tiến trình người dùng không khác gì so với việc bạn mã hóa các lệnh gọi fork (2) / exec (3) bằng ngôn ngữ bạn chọn. Shell là cha mẹ của bạn và nếu shell kết thúc (ví dụ: bạn đăng xuất), thì tiến trình con sẽ xuất hiện cùng với nó. Các sắc thái bạn mô tả chỉ là cách sửa đổi hành vi đó.

exec /path/to/programgiống như gọi exec (3) . Vâng, nó sẽ thay thế vỏ của bạn bằng program, giữ bất cứ thứ gì cha mẹ tung ra vỏ.

sh -c /path/to/programloại vô nghĩa tạo ra một quy trình vỏ con sẽ tạo ra một quy trình con program. Nó chỉ có giá trị nếu /path/to/programthực sự là một chuỗi các lệnh script và không phải là tệp thực thi. ( sh /path/to/script.shcó thể được sử dụng để chạy tập lệnh shell thiếu quyền thực thi trong trình bao kém hơn)

/path/to/programtạo ra một quy trình "tiền cảnh", nghĩa là cái vỏ chờ quá trình hoàn thành trước khi thực hiện bất kỳ hành động nào khác. Trong ngữ cảnh cuộc gọi hệ thống, nó giống như fork (2) / exec (3) / Waitpid (2) . Lưu ý rằng đứa trẻ thừa hưởng stdin / stdout / stderr từ cha mẹ.

/path/to/program &(bỏ qua chuyển hướng) tạo ra một "quá trình nền". Quá trình vẫn là một đứa con của vỏ, nhưng cha mẹ không chờ đợi nó chấm dứt.

nohup /path/to/programgọi nohup (1) để ngăn việc gửi SIGHUP tới programnếu thiết bị đầu cuối điều khiển bị đóng. Cho dù đó là ở nền trước hay nền là một lựa chọn (mặc dù thông thường nhất là quá trình được làm nền). Lưu ý rằng đó nohup.outchỉ là đầu ra nếu bạn không chuyển hướng thiết bị xuất chuẩn.

Khi bạn đặt một quy trình trong nền, nếu quy trình cha chết, một trong hai điều sẽ xảy ra. Nếu cha mẹ là thiết bị đầu cuối kiểm soát , thì SIGHUP sẽ được gửi cho trẻ em. Nếu không, thì quá trình có thể là "mồ côi" và được kế thừa bởi initquy trình.

Khi bạn chuyển hướng đầu vào / đầu ra / lỗi, bạn chỉ cần kết nối các bộ mô tả tệp mà mọi quy trình phải có các tệp khác với các tệp mà nó thừa hưởng từ cha mẹ của nó. Không ai trong số này ảnh hưởng đến quyền sở hữu quy trình hoặc độ sâu của cây (nhưng luôn có ý nghĩa khi chuyển hướng cả 3 từ một thiết bị đầu cuối cho các quy trình nền).

Với tất cả những gì đã nói, tôi không nghĩ bạn nên quan tâm đến việc tạo quy trình bằng vỏ hoặc vỏ phụ hoặc quy trình phụ, trừ khi có một vấn đề cụ thể mà bạn đang giải quyết liên quan đến quản lý quy trình.


nitpick: sh -c /path/to/programsẽ không chạy chương trình như một tập lệnh shell nếu nó thiếu các bit thực thi sh /path/to/program. sh -c /path/to/programsẽ chỉ mở một shell và chạy /path/to/programnhư một lệnh trong shell đó, nó sẽ thất bại nếu nó không được thực thi.
filbranden

Chà, nếu chúng ta đang nitpicking, cả hai chúng ta đều sai. sh -c /path/to/programđọc các lệnh từ /path/to/programđầu vào vỏ. Nó không yêu cầu tệp có quyền thực thi nhưng nó phải là tập lệnh shell
jwm

Hmmm, sh /path/to/programlàm điều đó. Chỉ cần thử bản thân mình : echo echo hello world >abc.sh, sau đó sh ./abc.shin hello world, trong khi sh -c ./abc.shnói sh: ./abc.sh: Permission denied(giống như khi bạn chạy ./abc.shtrực tiếp trong trình bao hiện tại.) Tôi có bỏ lỡ điều gì không? (Hoặc có lẽ tôi đã không thể hiện bản thân tốt trong bình luận trước đó ...)
filbranden

Lỗi của tôi. sh -c _something_cũng giống như chỉ cần gõ _something_tại dấu nhắc lệnh, ngoại trừ việc sinh ra lớp vỏ kém hơn. Vì vậy, bạn đúng rằng nó sẽ thất bại nếu thiếu bit thực thi (dưới dạng tệp). Mặt khác, bạn có thể cung cấp một loạt các lệnh shell như thế sh -c "echo hello world"và nó sẽ hoạt động tốt. Vì vậy, nó không yêu cầu những gì bạn nhập có bit thực thi (hoặc thậm chí là một tệp), chỉ có trình thông dịch shell có thể làm gì đó với nó.
jwm

Tôi tin rằng OP đã đề cập đến một số thực thi được biên dịch hoặc hệ thống, do đó, quyền thực thi đã được thừa nhận.
jwm
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.