Чи є спосіб для скрипта оболонки знати, яка програма його виконала?


13

Чи існує у * nix світі, чи є у сценарію оболонки інформація про те, яка програма його виконала?


Приклад:

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

у цьому уявному сценарії script_xyzматиме інформацію про шлях ( /path/to/script1)

або

обробити PID

суб'єкта господарювання, який його виконав.

Примітка: мені цікаво різні рішення та підходи, я не очікую, що саме це буде реально можливим


3
Тема запитує, яка програма виконувала сценарій. Але ваше власне питання, здається, запитує перекладача сценарію. Про кого з двох насправді йдеться у вашому питанні?
kasperd

@kasperd Ви праві. Питання стосувалося програми, але це насправді перекладач. Тому я відчував, що це в першу чергу неможливо.
Мілош Джаконович

Відповіді:


23

Часто виникає плутанина між форксуванням процесу та виконанням.

Коли ви робите підказки bashоболонки.

$ sh -c 'exec env ps'

Процес P1 видачі цього $підказка в даний час працює bashкодом. Цей bashкод розщеплює новий процес P2, який виконує, /bin/shякий потім виконує /usr/bin/env, який потім виконує /bin/ps.

Таким чином , P2 , в свою чергу виконується код bash, sh, envі ps.

ps(або будь-яка інша команда, як скрипт, яку ми б замість цього використали тут) не може знати, що вона виконується envкомандою.

Все, що він може зробити, - це з’ясувати, що таке його ідентифікатор батьківського процесу, який у цьому випадку буде P1 або 1якщо P1 загинув в інтервалі, або в Linux інший процес, який був призначений як підреактор замість 1.

Потім він може запитувати систему для того, яку команду цей процес виконує в даний момент (як, наприклад, 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міститиметься під батьківського процесу, який виконував оболонку під час ініціалізації цієї оболонки. Після цього, як видно вище, батьківський процес може змінитися, якщо процес ідентифікації $PPIDзагине.

zshв zsh/systemмодулі, може запитувати поточний батьківський під поточної (під-) оболонки за допомогою $sysparams[ppid]. В оболонках POSIX ви можете отримати поточний ppid процесу, який виконував інтерпретатор (якщо припустити, що він все ще працює) ps -o ppid= -p "$$". З bash, ви можете отримати ppid поточної (під-) оболонки за допомогою ps -o ppid= -p "$BASHPID".


8

Так, програма може знати, хто її батько.

Для ілюстрації давайте створимо два сценарії bash. Перший повідомляє про свій PID та запускає другий сценарій:

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

Другий скрипт повідомляє про його ідентифікатор процесу, 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 свого батьківського. Використовуючи ps, що PID розкриває командний рядок, який використовується для виклику батьків.

Для обговорення PPID в більшій глибині, см Stéphane Chazelas в відповідь .


Спасибі. Запуск ваших прикладів скриптів , які я отримую s1, s2і PPIDзначення , але потім, в декількох рядках , після ERROR: Unsupported SysV option.і кілька ліній з додатковим поясненням і - пусте значення дляParent command
Мілош Đakonović

Джон використовує якусь функцію ps, яка недоступна (або надається по-різному) на вашій платформі, перегляньте сторінку керівництва ps (1).
Ясен

@Miloshio Я тестував вище , з використанням psз procps-ngпакета, версії 3.3.12. Як запропонував Ясен, ви, ймовірно, використовуєте іншу версію, яка може вимагати іншого синтаксису для друку батьківського командного рядка. Спробуйте ps -f | grep $PPID.
John1024
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.