Nhận PID của bất kỳ lệnh nào trong chuỗi lệnh được quét nền


11

Nếu, trong bash, tôi thực thi:

cmd1 | cmd2 | ... | cmdi | ... | cmdn &

Trường hợp cmd{1..n}có thể không khác biệt, làm thế nào để tôi có được PID cmdi? Ngoài ra, làm thế nào tôi có thể báo hiệu cmdiquá trình? (Ví dụ: gửi nó SIGUSR1?) pkill/ pgrep, pidofV.v. không giống như câu trả lời hay, vì các trường hợp khác cmdicó thể đang chạy, bao gồm cả một phần của cùng một đường ống. jobs -pcung cấp cho PID của cmd1, cho tôi.

icó thể là bất cứ điều gì trong {1..n}.



1
@ G-Man Chăm sóc để giải thích? Tôi chỉ thấy sự tương đồng bề ngoài, và như tôi đã giải thích trong câu trả lời của Ramesh, việc sửa đổi bộ lệnh không được sử dụng nhiều.
muru

Bề ngoài tương đồng? cat /var/run/out | nc -l 8080chỉ là bề ngoài tương tự để cmd1 | cmd2? Hạn chế của bạn, rằng bạn muốn nhập đường ống xương trần và sau đó phục hồi các PID, là (1) không được nêu trong câu hỏi và (2) không thể cho phép một giải pháp chung, tốt.
G-Man nói 'Phục hồi Monica'

@ G-Man Ngược lại, bạn đang áp đặt các ràng buộc mà đơn giản không được nêu. cmd1 | cmd2là một trường hợp rất đặc biệt khi cả hai PID đều có thể dễ dàng lấy được. Tôi có nói gì về n không? Vậy tại sao bạn lại giả sử n = 2? Tôi đã nói bất cứ điều gì về cmdi là gì? Vậy tại sao bạn cho rằng tôi có thể sửa đổi cmdi? Tôi đang yêu cầu một giải pháp chung và bạn đang áp đặt các hạn chế.
muru

Câu trả lời:


6

Đối với phiên bản gốc của câu hỏi, khi chỉ mong muốn lệnh PID cuối cùng, biến đặc biệt $!là hoàn hảo.

foo | bar | baz &
baz_pid=$!

Không có quyền truy cập dễ dàng tương tự vào các PID của các quá trình khác.

Phải mất một thời gian dài để $pipestatus(zsh) và $PIPESTATUS(bash) được thêm vào, cuối cùng cho phép chúng tôi truy cập vào tất cả các trạng thái thoát trong một đường ống, ngoài trạng thái $?cuối cùng đã có từ vỏ Bourne ban đầu. Có lẽ một cái gì đó tương tự sẽ xảy ra với $!cuối cùng.


Bạn có phiền nếu tôi chỉnh sửa câu hỏi để yêu cầu PID của một lệnh tùy ý trong danh sách không? Hay tôi nên bắt đầu một câu hỏi mới?
muru

Có lẽ bạn sẽ phải chờ rất lâu để có câu trả lời cho câu hỏi đó. Tôi không có cảm xúc mạnh mẽ về tổ chức trang web stackexchange nên câu hỏi riêng biệt, chỉnh sửa câu hỏi, bất cứ điều gì ... sẽ không làm phiền tôi

Không sao, vấn đề trước mắt đã được giải quyết, bây giờ sự tò mò đã được giải quyết. Tôi sẽ chỉnh sửa nó sau đó. Chỉ là một cái đầu, vì tôi đã thấy các câu hỏi thay đổi mạnh mẽ và để lại những câu trả lời cũ hơn trông rất lạc lõng.
muru

@muru - lưu ý rằng sẽ tốt hơn nếu biến nó thành Q mới tham chiếu cái này.
slm

@slm ghi chú hợp lệ. Sẽ làm như vậy trong tương lai.
muru

4

Tôi nghĩ rằng bạn có thể làm một cái gì đó như đề nghị ở đây .

(ls -l | echo "Hello" | df -h & echo $! >&3 ) 3>pid

Ở đây trong ví dụ trên, tôi đã lấy pid của quá trình đường ống thứ ba và ghi chú nó vào tệp pid. Tôi có thể lưu ý nó xuống cho bất kỳ quá trình đường ống.


Thú vị, nhưng điều này sẽ liên quan đến việc sửa đổi bộ lệnh. Không sử dụng nhiều một khi các lệnh đã được thực thi.
muru

@muru - cái gì? sử dụng bất kỳ PID nào khi nó đã thực hiện xong? Bạn có muốn PID của đường ống? jobs -p. báo hiệu với SIGPIPE. Bạn có muốn cmdi- cái này
mikeerv

1
@mikeerv Không phải nếu họ ở trong nền, chạy như chúng ta nói. Bằng cách phù thủy nào tôi phải sửa đổi dòng lệnh cho điều đó?
muru

1
@muru đó sẽ là một phép thuật. bạn cần một trình sửa lỗi
mikeerv

Tôi thấy đây là một mô hình hữu ích để bắt đầu các quá trình nền, chờ chúng đến trạng thái nào đó và sau đó giết chúng. Trong trường hợp bất cứ ai quan tâm: gist.github.com/MatrixManAtYrService/...
MatrixManAtYrService

2

Một giải pháp dành riêng cho Linux, không di động, có thể theo dõi các quy trình bằng cách sử dụng các đường ống kết nối chúng. Chúng ta có thể nhận được các PID của các lệnh đầu tiên ( jobs -p) và cuối cùng ( $!) trong đường ống. Sử dụng một trong hai PID, tập lệnh này có thể thực hiện công việc:

#! /bin/bash

PROC=$1
echo $PROC

if [[ $(readlink /proc/$PROC/fd/1) =~ ^pipe: ]]
then
    # Assuming first process in chain...
    NEXT_FD=1
elif [[ $(readlink /proc/$PROC/fd/0) =~ ^pipe: ]]
then
    # Last process in chain...
    NEXT_FD=0
else
    # Doesn't look like a pipe.
    exit
fi

NEXT_PROC_PIPE=$(readlink /proc/$PROC/fd/$NEXT_FD)

while [[ $NEXT_PROC_PIPE =~ ^pipe: ]] 
do
    PROC=$(find /proc/*/fd -type l -printf "%p/%l\n" 2>/dev/null | awk -F'/' '($6 == "'"$NEXT_PROC_PIPE"'") && ($3 != "'$PROC'" ) {print $3}')
    NEXT_PROC_PIPE=$(readlink /proc/$PROC/fd/$NEXT_FD)
    echo $PROC
done

Đối với người hiếu, có thêm về loại điều ở đây: unix.stackexchange.com/a/486233/146169
MatrixManAtYrService

0

Tôi sử dụng mảng dựa trên zero ở đây trong mã này. Chỉ cần cẩn thận những gì bạn chạy qua eval.

#!/bin/bash

cmd=('sleep 10' 'sleep 2' 'sleep 5')
first=1
for c in "${cmd[@]}"; do
  ((first)) && { pipe=$c; first=0; } || pipe+='|'$c
done
shopt -u lastpipe
eval $pipe &

printf 'Pipe:\n%s\n\n' "$pipe"

shellpid=$BASHPID
parent=$(ps -o pid= --ppid $shellpid | head -n -1)
declare -a pids=()
mapfile -t pids < <(printf '%s\n' $(ps -o pid= --ppid $parent))
printf '%s\n' 'Listing the arrays:'
printf '%2s %6s %s\n' i PID command
for i in "${!cmd[@]}"; do
    printf '%2d %6d %s\n' "$i" "${pids[i]}" "${cmd[i]}"
done

printf '\n%s\n' 'ps listing:'
ps xao pid,ppid,command | head -n 1
ps xao pid,ppid,command | tail | head -n -3
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.