รับ PID ของคำสั่งใด ๆ ในลำดับของ piped ของคำสั่ง


11

ถ้า, ในbash, ฉันเรียกใช้งาน:

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

ในกรณีที่cmd{1..n}ไม่ชัดเจนฉันจะได้รับ PID ได้cmdiอย่างไร อีกวิธีหนึ่งฉันจะส่งสัญญาณcmdiกระบวนการได้อย่างไร (ตัวอย่างเช่นส่งSIGUSR1?) pkill/ pgrep, pidofฯลฯ ดูไม่เหมือนคำตอบที่ดีเนื่องจากกรณีอื่น ๆcmdiอาจจะทำงานรวมทั้งเป็นส่วนหนึ่งของท่อเดียวกัน jobs -pให้ PID ของcmd1สำหรับฉัน

i{1..n}สามารถเป็นอะไรก็ได้ใน



1
@G-Man Care ที่จะอธิบาย? ฉันเห็นความคล้ายคลึงกันเพียงผิวเผินเท่านั้นและตามที่ฉันอธิบายในคำตอบของ Ramesh การแก้ไขชุดคำสั่งไม่ได้ใช้งานมากนัก
muru

ความคล้ายคลึงกันตื้น ๆ ? cat /var/run/out | nc -l 8080เป็นเพียงผิวเผินเท่านั้นที่จะcmd1 | cmd2? ข้อ จำกัด ของคุณที่คุณต้องการพิมพ์ไปป์ไลน์เปลือยแล้วกู้คืน PID คือ (1) ไม่ได้ระบุไว้ในคำถามและ (2) ไม่น่าจะอนุญาตวิธีแก้ปัญหาทั่วไปที่ดี
G-Man กล่าวว่า 'Reinstate Monica'

@ G-Man ในทางตรงกันข้ามคุณกำลังกำหนดข้อ จำกัด ที่ไม่ง่าย cmd1 | cmd2เป็นกรณีพิเศษมากที่สามารถขอรับ PID ทั้งสองได้อย่างง่ายดาย ฉันพูดอะไรเกี่ยวกับ n หรือไม่? แล้วทำไมคุณถึงคิดว่า n = 2 ฉันพูดอะไรเกี่ยวกับสิ่งที่ cmdi คืออะไร? แล้วทำไมคุณถึงคิดว่าฉันสามารถแก้ไข cmdi ได้? ฉันกำลังขอวิธีแก้ไขปัญหาทั่วไปและคุณกำลังกำหนดข้อ จำกัด
muru

คำตอบ:


6

สำหรับคำถามรุ่นดั้งเดิมเมื่อต้องการเพียง PID ของคำสั่งสุดท้ายตัวแปรพิเศษ$!นั้นสมบูรณ์แบบ

foo | bar | baz &
baz_pid=$!

ไม่มีการเข้าถึง PIDs ของกระบวนการอื่นที่คล้ายกัน

ใช้เวลานานในการเพิ่ม$pipestatus(zsh) และ$PIPESTATUS(bash) ในที่สุดทำให้เราสามารถเข้าถึงสถานะทางออกทั้งหมดในไปป์ไลน์ได้นอกจากนี้$?สำหรับสุดท้ายที่อยู่รอบ ๆ ตั้งแต่เชลล์เป้าหมายเดิม บางทีสิ่งที่คล้ายคลึงจะเกิดขึ้น$!ในที่สุด


คุณจะรังเกียจไหมถ้าฉันแก้ไขคำถามเพื่อขอ PID ของคำสั่งโดยพลการในรายการด้วย? หรือฉันควรเริ่มคำถามใหม่?
muru

คุณอาจต้องรออีกนานกว่าจะได้คำตอบ ผมไม่ได้มีความรู้สึกที่ดีเกี่ยวกับองค์กรเว็บไซต์ stackexchange ดังนั้นคำถามที่แยกจากกันแก้ไขคำถามสิ่งที่ ... จะไม่รำคาญฉัน

ไม่เป็นไรปัญหาเร่งด่วนได้รับการแก้ไขแล้วตอนนี้อยากรู้อยากเห็นอยู่ในความดูแล ฉันจะแก้ไขมันแล้ว เพียงแค่หัวขึ้นเนื่องจากฉันได้เห็นคำถามที่เปลี่ยนไปอย่างมากและออกจากคำตอบที่เก่ามองออกนอกสถานที่มาก
muru

@muru - โปรดทราบว่ามันจะดีกว่าถ้าจะให้เป็น Q ตัวใหม่ที่อ้างอิงตัวนี้
slm

@slm ตั้งข้อสังเกตอย่างถูกต้อง จะทำเช่นนั้นในอนาคต
muru

4

ฉันคิดว่าคุณสามารถทำสิ่งที่เป็นข้อเสนอแนะที่นี่

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

ในตัวอย่างด้านบนฉันได้เรียก pid ของกระบวนการ piped ที่สามและจดบันทึกลงใน pid ไฟล์ ฉันสามารถจดบันทึกไว้สำหรับกระบวนการตามลำดับ


น่าสนใจ แต่สิ่งนี้จะเกี่ยวข้องกับการแก้ไขชุดคำสั่ง ไม่ค่อยมีใครใช้เมื่อคำสั่งถูกเรียกใช้งาน
muru

@muru - อะไรนะ PID ใดที่ใช้งานได้เมื่อดำเนินการเสร็จสิ้นแล้ว คุณต้องการ PID ของท่อส่งก๊าซหรือไม่? jobs -p. SIGPIPEสัญญาณมันด้วย คุณต้องการcmdi- นี่
mikeserv

1
@mikeserv ไม่ได้ถ้าพวกเขาอยู่ในพื้นหลังทำงานในขณะที่เราพูด ข้าควรจะใช้เวทมนตร์อะไรในการปรับเปลี่ยนบรรทัดคำสั่ง
muru

1
@muru นั้นน่าจะเป็นศาสตร์เวท คุณต้องการดีบักเกอร์
mikeserv

ฉันคิดว่านี่เป็นรูปแบบที่มีประโยชน์สำหรับการเริ่มต้นกระบวนการพื้นหลังรอให้พวกเขาไปถึงบางสถานะแล้วฆ่าพวกเขา ในกรณีที่ใครสนใจ: gist.github.com/MatrixManAtYrService/ ...
MatrixManAtYrService

2

โซลูชันเฉพาะของ Linux ที่ไม่พกพาได้อาจใช้ติดตามกระบวนการโดยใช้ไพพ์ที่เชื่อมต่อ เราสามารถรับ PID ของคำสั่งแรก ( jobs -p) และสุดท้าย ( $!) ในไปป์ไลน์ การใช้ PID อย่างใดอย่างหนึ่งสคริปต์นี้สามารถทำงาน:

#! /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

สำหรับสิ่งที่อยากรู้อยากเห็นเพิ่มเติมเกี่ยวกับสิ่งต่าง ๆ ที่นี่: unix.stackexchange.com/a/486233/146169
MatrixManAtYrService

0

ฉันใช้อาร์เรย์ zero-based ที่นี่ในรหัสนี้ 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.