มีวิธีใดบ้างที่เชลล์สคริปต์จะรู้ว่าโปรแกรมใดทำงานหรือไม่


13

ใน * nix world มีวิธีใดที่เชลล์สคริปต์จะมีข้อมูลเกี่ยวกับโปรแกรมที่เรียกใช้งานหรือไม่


ตัวอย่าง:

/path/to/script1 /path/to/script_xyz

ในสถานการณ์สมมตินี้script_xyzจะมีข้อมูลเส้นทาง ( /path/to/script1)

หรือ

ประมวลผล PID

ของนิติบุคคลที่ได้ดำเนินการ

หมายเหตุ: ฉันอยากรู้เกี่ยวกับการแก้ปัญหาและแนวทางที่แตกต่างกันฉันไม่คาดหวังว่าสิ่งนี้จะเป็นไปได้จริง


3
หัวเรื่องของคุณถามว่าโปรแกรมใดที่เรียกใช้สคริปต์ แต่คำถามที่แท้จริงของคุณดูเหมือนจะขอล่ามของสคริปต์ คำถามของคุณสองข้อไหน
kasperd

@kasperd คุณพูดถูก คำถามเกี่ยวกับโปรแกรม แต่เป็นล่ามจริง นั่นเป็นเหตุผลที่ฉันรู้สึกว่ามันเป็นไปไม่ได้ในตอนแรก
MilošĐakonović

คำตอบ:


23

มักมีความสับสนระหว่างการฟอร์กกระบวนการและการดำเนินการ

เมื่อคุณทำตามคำสั่งของbashเชลล์

$ sh -c 'exec env ps'

กระบวนการP1 ที่ออก$พรอมต์นั้นกำลังเรียกใช้bashรหัสในปัจจุบัน นั่นbashรหัสส้อมกระบวนการใหม่P2ที่รัน/bin/shซึ่งจากนั้นจะดำเนินการที่แล้วรัน/usr/bin/env/bin/ps

ดังนั้นP2ได้ในการเปิดดำเนินการของรหัสbash, sh, และenvps

ps(หรือคำสั่งอื่น ๆ เช่นสคริปต์ที่เราจะใช้แทนที่นี่) ไม่มีทางที่จะรู้ว่ามันถูกใช้งานโดยenvคำสั่ง

ทั้งหมดก็สามารถทำได้คือการหาสิ่งที่กระบวนการ id แม่เป็นซึ่งในกรณีนี้จะเป็นได้ทั้งP1หรือ1ถ้าP1ได้ตายในช่วงเวลาหรือบนลินุกซ์กระบวนการอื่นที่ได้รับการกำหนดให้เป็นsubreaper1แทน

จากนั้นสามารถสืบค้นระบบสำหรับคำสั่งที่กระบวนการกำลังทำงานอยู่ (เช่นเดียวกับreadlink /proc/<pid>/exeบน Linux) หรืออาร์กิวเมนต์ใดที่ส่งผ่านไปยังคำสั่งสุดท้ายที่เรียกใช้งาน (เช่นเดียวกับps -o args= -p <pid>)

หากคุณต้องการให้สคริปต์ของคุณรู้ว่าสิ่งใดที่ถูกเรียกใช้วิธีที่เชื่อถือได้ก็คือให้ผู้เรียกใช้บอกมัน ที่สามารถทำได้เช่นผ่านตัวแปรสภาพแวดล้อม ตัวอย่างเช่นscript1สามารถเขียนเป็น:

#! /bin/sh -
INVOKER=$0 script2 &

และscript2:

#! /bin/sh -
printf '%s\n' "I was invoked by $INVOKER"
# and in this case, we'll probably find the parent process is 1
# (if not now, at least one second later) as script1 exited just after
# invoking script2:
ps -fp "$$"
sleep 1
ps -fp "$$"
exit

$INVOKERจะ ( ทั่วไป ) script1ประกอบด้วยเส้นทางไปยัง ในบางกรณีอาจเป็นเส้นทางสัมพัทธ์แม้ว่าและเส้นทางจะสัมพันธ์กับไดเรกทอรีทำงานปัจจุบัน ณ เวลาที่script1เริ่มต้น ดังนั้นหากscript1มีการเปลี่ยนแปลงไดเรกทอรีการทำงานปัจจุบันก่อนที่จะเรียกscript2, script2จะได้รับข้อมูลที่ไม่ถูกต้องเป็นสิ่งที่เรียกว่า ดังนั้นจึงอาจดีกว่าเพื่อให้แน่ใจว่า$INVOKERมีเส้นทางที่แน่นอน (โดยเฉพาะการรักษาชื่อเบส) เช่นโดยการเขียนscript1เป็น:

#! /bin/sh -
mypath=$(
  mydir=$(dirname -- "$0") &&
  cd -P -- "$mydir" &&
  pwd -P) && mypath=$mypath/$(basename -- "$0") || mypath=$0

... some code possibly changing the current working directory
INVOKER=$mypath script2

ใน POSIX เชลล์$PPIDจะประกอบด้วย pid ของพาเรนต์ของกระบวนการที่ดำเนินการเชลล์ในเวลาที่การเริ่มต้นเชลล์นั้น หลังจากนั้นตามที่เห็นด้านบนกระบวนการผู้ปกครองอาจเปลี่ยนแปลงหากกระบวนการของ id $PPIDตาย

zshในzsh/systemโมดูลสามารถสอบถามปัจจุบัน pid แม่ของปัจจุบัน (ย่อย) $sysparams[ppid]เปลือก ในเปลือกหอย POSIX, คุณจะได้รับในปัจจุบัน PPID ของกระบวนการที่ดำเนินการล่าม (สมมติว่ามันยังทำงานอยู่) ps -o ppid= -p "$$"กับ ด้วยbashคุณจะได้รับ PPID ของปัจจุบัน (ย่อย) ps -o ppid= -p "$BASHPID"เปลือกกับ


8

ใช่โปรแกรมสามารถรู้ได้ว่าใครเป็นผู้ปกครอง

เพื่ออธิบายให้สร้างสคริปต์ทุบตีสองตัว คนแรกรายงาน PID ของมันและเริ่มสคริปต์ที่สอง:

$ cat s1.sh
#!/bin/bash
echo s1=$$
bash s2.sh

สคริปต์ที่สองรายงาน ID กระบวนการ PID ของพาเรนต์และบรรทัดคำสั่งที่ใช้เพื่อรันพาเรนต์:

$ cat s2.sh
#!/bin/bash
echo s2=$$ PPID=$PPID
echo "Parent command: $(ps -o cmd= -q $PPID)"

ตอนนี้ให้เรียกใช้:

$ bash s1.sh
s1=17955
s2=17956 PPID=17955
Parent command: bash s1.sh

อย่างที่คุณเห็นว่าสคริปต์ที่สองทำจริง ๆ แล้วรู้จัก PID ของผู้ปกครอง การใช้psPID นั้นจะแสดงบรรทัดคำสั่งที่ใช้เรียกพาเรนต์

สำหรับการอภิปรายของ PPID ในเชิงลึกเพิ่มเติมให้ดูStéphane Chazelas ของคำตอบ


ขอบคุณ เล่นสคริปต์ของคุณตัวอย่างเช่นฉันจะได้รับs1, s2และPPIDค่า แต่แล้วในหลายบรรทัดหลังERROR: Unsupported SysV option.และอีกหลายสายที่มีคำอธิบายเพิ่มเติมและ - ค่าว่างสำหรับParent command
MilošĐakonović

John ใช้คุณสมบัติ ps บางอย่างที่ไม่พร้อมใช้งาน (หรือมีให้แตกต่างกัน) บนแพลตฟอร์มของคุณตรวจสอบหน้าคู่มือ ps (1) ของคุณ
Jasen

@Miloshio ฉันทดสอบข้างต้นใช้psจากprocps-ngแพคเกจรุ่น 3.3.12 ตามที่ Jasen แนะนำคุณมีแนวโน้มที่จะใช้เวอร์ชันอื่นซึ่งอาจต้องใช้ไวยากรณ์ที่แตกต่างกันสำหรับการพิมพ์บรรทัดคำสั่งของผู้ปกครอง ลองps -f | grep $PPIDดู
John1024
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.