Вот
#!/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 }
Это действительно странное требование. Зачем вам все равно, какая интерактивная оболочка вызвала ваш скрипт или какую-то другую программу, которая не является интерактивной оболочкой, которая, в свою очередь, вызвала ваш скрипт? Это очень сильно пахнет проблемой XY .
ЕСЛИ вам действительно нужно знать, вы можете попытаться выяснить это, но я не думаю, что есть полностью надежный метод, только тот, который работает в типичных случаях.
Начиная с $ PPID
, отслеживайте процессы-предки вашего скрипта ( ps -o ppid = -p $ ancestor_pid
), пока не найдете тот, который ищете, или тот, который указывает на то, что вы зашли слишком далеко.
Простая стратегия - искать процесс в другой группе процессов ( ps -o pgid = -p $ ancestor_pid
). При нормальных обстоятельствах, если ваш сценарий был вызван (сценарий, который был вызван) интерактивной оболочкой, этот процесс, который вы достигли, представляет собой оболочку с управлением заданиями, которая запускала ваш сценарий (родительский сценарий) в отдельной группе процессов. .
Вот несколько примеров того, что может пойти не так с этой стратегией:
Вы можете или не можете захотеть проверить, что стандартный ввод, стандартный вывод и стандартная ошибка этого процесса (например, с lsof
или через / proc
, если вам не нужна переносимость за пределами Linux) - это тот же терминал, что и ваш скрипт. Это зависит от того, как вы хотите обрабатывать такие случаи, как
bash$ xterm -e your_script
Вы проверяете его параметры.
[ "$-" = "${-#*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. Управление заданиями так же связано с интерактивной оболочкой, как и терминал, просто терминал - это более прямой способ проверить это.