Как получить имя ближайшей интерактивной оболочки-предка из сценария?

Вот

#!/usr/local/bin/awk -f 

{       
        ns = 0
        while(NF > 0) {
                for(i = 0; i < ns; i++) printf " "
                print
                for(i = 1; i < NF; i++) {
                        $i = abs($i-$(i+1))
                }       
                NF--
                ns++
        }       
}       

function abs(x) { return x < 0 ? -x : x }
2
01.07.2016, 17:47
2 ответа

Это действительно странное требование. Зачем вам все равно, какая интерактивная оболочка вызвала ваш скрипт или какую-то другую программу, которая не является интерактивной оболочкой, которая, в свою очередь, вызвала ваш скрипт? Это очень сильно пахнет проблемой XY .

ЕСЛИ вам действительно нужно знать, вы можете попытаться выяснить это, но я не думаю, что есть полностью надежный метод, только тот, который работает в типичных случаях.

Начиная с $ PPID , отслеживайте процессы-предки вашего скрипта ( ps -o ppid = -p $ ancestor_pid ), пока не найдете тот, который ищете, или тот, который указывает на то, что вы зашли слишком далеко.

Простая стратегия - искать процесс в другой группе процессов ( ps -o pgid = -p $ ancestor_pid ). При нормальных обстоятельствах, если ваш сценарий был вызван (сценарий, который был вызван) интерактивной оболочкой, этот процесс, который вы достигли, представляет собой оболочку с управлением заданиями, которая запускала ваш сценарий (родительский сценарий) в отдельной группе процессов. .

Вот несколько примеров того, что может пойти не так с этой стратегией:

  • Один из процессов в этой цепочке уже мертв.
  • Ваш сценарий был вызван не через интерактивную оболочку, а через задание cron, из программы X11 и т. Д.

Вы можете или не можете захотеть проверить, что стандартный ввод, стандартный вывод и стандартная ошибка этого процесса (например, с lsof или через / proc , если вам не нужна переносимость за пределами Linux) - это тот же терминал, что и ваш скрипт. Это зависит от того, как вы хотите обрабатывать такие случаи, как

bash$ xterm -e your_script
3
27.01.2020, 21:56

Вы проверяете его параметры.

[ "$-" = "${-#*i}" ] ||
echo shell is interactive

Вы также можете проверить его файловые дескрипторы. Это немного другое. Он не обязательно скажет вам, является ли оболочка интерактивной как таковой, но он сообщит вам, общается ли она с терминалом.

for fd in 0 1 2
do     [ -t "$fd" ] && 
       break 
done|| echo shell fds 0 1 2 are not connected to a terminal.

Мы можем немного взломать это, чтобы попытаться обнаружить все используемые процессы нашего терминала.

tty_users()
    for fd in 0 1 2 "$@"
    do     [ -t "$fd" ] && {
           fuser "$(tty)"
           break; } <&"$fd"
    done 

Которая будет запущена в текущей оболочке и распечатает список идентификаторов процессов для тех процессов, которые запущены на первом обнаруженном терминале, как связанные с std (in | out | err) (по умолчанию - передать функцию числовые аргументы для проверки других) соответственно. Он устанавливает для оболочки var $ fd номер дескриптора файла, связанный с этим терминалом, и возвращает false, если ни один из стандартных дескрипторов или каких-либо аргументов не связан с терминалом.

Вышеупомянутое, вероятно, так близко, как вы получите, если вы не поищете идентификатор сеанса вашего терминала - если он у вас есть.

ps -osid= -p"$$"

Это вернет вам pid владельца вашего управляющего терминала - если он у вас есть.

Чтобы продемонстрировать:

echo "$$"; sh -c 'sh -c "ps -osid= -p\"\$$\""' 

6023
6023

Но вы не можете полагаться ни на что из этого. Вовсе нет. Смотрите:

sh -acm 'IFS=\; i=0;eval "$0"'          \
        '[ "$i" -lt 5 ] && eval "$*"'   \
        'ps -opid -opgid -p"$$"'        \
        'sh -acm "$0" "$0" "$@" i=$((i+=1))'
  PID  PGID
28766 28766
  PID  PGID
28768 28768
  PID  PGID
28770 28770
  PID  PGID
28772 28772
  PID  PGID
28774 28774

Видите? Интерактивной оболочки, из которой я запускаю эти процессы, нет даже в этом списке. Каждый sh запускает собственный дочерний элемент, пока не будет достигнута глубина 5, и при каждом запуске вызывает ps для печати своего PID и PGID. Каждый процесс получает новый PGID. Управление заданиями так же связано с интерактивной оболочкой, как и терминал, просто терминал - это более прямой способ проверить это.

2
27.01.2020, 21:56

Теги

Похожие вопросы