Có cách nào để shell script biết chương trình nào đã thực thi nó không?


13

Trong thế giới * nix, có cách nào để shell script có thông tin về chương trình nào đã thực hiện nó không?


Thí dụ:

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

trong kịch bản tưởng tượng này, script_xyzsẽ có thông tin đường dẫn ( /path/to/script1)

hoặc là

quy trình PID

của thực thể đã thực hiện nó.

Lưu ý: Tôi tò mò về các giải pháp và cách tiếp cận khác nhau, tôi không mong đợi chính xác điều này sẽ thực sự khả thi


3
Đối tượng của bạn hỏi chương trình nào thực hiện kịch bản. Nhưng câu hỏi thực tế của bạn dường như đang yêu cầu người phiên dịch kịch bản. Câu hỏi nào trong hai câu hỏi của bạn?
kasperd

@kasperd Bạn nói đúng. Câu hỏi là về chương trình, nhưng đó thực sự là thông dịch viên. Đó là lý do tại sao tôi cảm thấy rằng điều này là không thể ngay từ đầu.
Miloš Đakonović

Câu trả lời:


23

Thường có sự nhầm lẫn giữa quá trình rèn và thực hiện.

Khi bạn làm tại dấu nhắc của một bashvỏ.

$ sh -c 'exec env ps'

Quá trình phát hành P1 đó $hiện đang chạy bashmã. bashMã đó tạo ra một quy trình P2 mới thực thi /bin/sh, sau đó thực thi /usr/bin/env, sau đó thực thi /bin/ps.

Vì vậy, P2 đã lần lượt thực hiện quy tắc ứng bash, sh, envps.

ps(hoặc bất kỳ lệnh nào khác như tập lệnh mà chúng ta sẽ sử dụng thay vào đây) không có cách nào để biết rằng nó đã được thực thi bởi envlệnh.

Tất cả những gì có thể làm là tìm ra id tiến trình mẹ của nó là gì, trong trường hợp này sẽ là P1 hoặc 1nếu P1 đã chết trong khoảng thời gian hoặc trên Linux, một quy trình khác được chỉ định là một phản ứng phụ thay vì 1.

Sau đó, nó có thể truy vấn hệ thống về lệnh nào mà quá trình đó hiện đang chạy (như với readlink /proc/<pid>/exeLinux) hoặc đối số nào được chuyển đến lệnh cuối cùng mà nó đã thực thi (như với ps -o args= -p <pid>).

Nếu bạn muốn kịch bản của bạn biết cái gì đã gọi nó, một cách đáng tin cậy sẽ là người mời nói với nó. Điều đó có thể được thực hiện ví dụ thông qua một biến môi trường. Ví dụ script1có thể được viết là:

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

$INVOKERsẽ ( nói chung ) chứa một đường dẫn đến script1. Trong một số trường hợp, nó có thể là một đường dẫn tương đối và đường dẫn sẽ liên quan đến thư mục làm việc hiện tại tại thời điểm script1bắt đầu. Vì vậy, nếu script1thay đổi thư mục làm việc hiện tại trước khi gọi script2, script2sẽ nhận được thông tin sai như những gì đã gọi nó. Vì vậy, có thể tốt hơn để đảm bảo $INVOKERchứa một đường dẫn tuyệt đối (tốt nhất là giữ tên cơ sở) như bằng cách viết script1như sau:

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

Trong shell POSIX, $PPIDsẽ chứa pid của cha mẹ của quá trình thực thi shell tại thời điểm khởi tạo shell đó. Sau đó, như đã thấy ở trên, quy trình cha có thể thay đổi nếu quá trình id $PPIDchết.

zshtrong zsh/systemmô-đun, có thể truy vấn pid cha hiện tại của shell (sub-) hiện tại với $sysparams[ppid]. Trong shell POSIX, bạn có thể nhận được ppid hiện tại của quá trình thực thi trình thông dịch (giả sử nó vẫn đang chạy) ps -o ppid= -p "$$". Với bash, bạn có thể lấy ppid của shell (sub-) hiện tại với ps -o ppid= -p "$BASHPID".


8

Vâng, một chương trình có thể biết cha mẹ của nó là ai.

Để minh họa, hãy tạo hai tập lệnh bash. Cái đầu tiên báo cáo PID của nó và bắt đầu tập lệnh thứ hai:

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

Kịch bản thứ hai báo cáo ID tiến trình của nó, PID của cha mẹ và dòng lệnh được sử dụng để chạy cha mẹ:

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

Bây giờ, hãy chạy nó:

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

Như bạn có thể thấy tập lệnh thứ hai, trên thực tế, biết bộ vi xử lý cha mẹ của nó. Sử dụng ps, PID đó cho thấy dòng lệnh được sử dụng để gọi cha mẹ.

Để thảo luận về PPID sâu hơn, xem câu trả lời của Stéphane Chazelas .


Cảm ơn. Chạy kịch bản của bạn ví dụ tôi có được s1, s2PPIDgiá trị nhưng sau đó, trong nhiều dòng sau ERROR: Unsupported SysV option.và một vài dòng với lời giải thích bổ sung và - giá trị rỗng choParent command
Miloš Đakonović

John đang sử dụng một số tính năng ps không khả dụng (hoặc được cung cấp khác) trên nền tảng của bạn, hãy kiểm tra trang hướng dẫn ps (1) của bạn.
Jasen

@Miloshio Tôi đã thử nghiệm trên sử dụng pstừ procps-nggói, phiên bản 3.3.12. Như Jasen đề xuất, bạn có thể sử dụng một phiên bản khác có thể yêu cầu một cú pháp khác để in dòng lệnh của cha mẹ. Hãy thử ps -f | grep $PPID.
John1024
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.