Сколько снарядов я глубоко?

Проблема : найдите, сколько снарядов я глубоко.

Подробности : я открываю оболочку из vim. Сборка, запуск и выход. Иногда я забываю и открываю еще один вим внутри, а затем еще одну оболочку. 🙁

Я хочу знать, сколько у меня снарядов, возможно, даже на моем экране оболочки всегда. (Я могу управлять этой частью).

Мое решение : проанализируйте дерево процессов и найдите vim и bash / zsh и определите глубину текущего процесса внутри него.

Что-то подобное уже существует? Я ничего не мог найти.

7 Solutions collect form web for “Сколько снарядов я глубоко?”

Когда я прочитал ваш вопрос, моя первая мысль была $SHLVL . Затем я увидел, что вы хотели подсчитать уровни vim в дополнение к уровням оболочки. Простой способ сделать это – определить функцию оболочки:

 vim() { ( ((SHLVL++)); command vim "$@");} 

Это будет автоматически и тихо увеличивать SHLVL каждый раз, когда вы вводите команду vim . Вам нужно будет сделать это для каждого варианта vi / vim который вы когда-либо использовали; например,

 vi() { ( ((SHLVL++)); command vi "$@");} view() { ( ((SHLVL++)); command view "$@");} 

Внешний набор круглых скобок создает подоболочку, поэтому ручное изменение значения SHLVL не загрязняет текущую (родительскую) оболочку. Конечно, ключевое слово command существует, чтобы функции не вызывали себя (что привело бы к бесконечному циклу рекурсии). И, конечно, вы должны поместить эти определения в ваш .bashrc или другой файл инициализации оболочки.


В приведенной выше приведена небольшая неэффективность. В некоторых оболочках (bash – один), если вы говорите

  ( cmd 1 , cmd 2 , ... ; cmd n ) 

где cmd n – внешняя исполняемая программа (т. е. не встроенная команда), оболочка содержит дополнительный процесс, лежащий вокруг, просто для ожидания завершения cmd n . Это (возможно) не обязательно; преимущества и недостатки являются спорными. Если вы не возражаете связывать немного памяти и слот процесса (и видеть еще один процесс оболочки, чем вам нужно, когда вы делаете ps ), выполните вышеописанное и перейдите к следующему разделу. То же самое, если вы используете оболочку, которая не удерживает лишний процесс. Но, если вы хотите избежать дополнительного процесса, сначала попробуйте

 vim() { ( ((SHLVL++)); exec vim "$@");} 

Команда exec предназначена для предотвращения затягивания дополнительного процесса оболочки.

Но есть что-то. Обработка оболочки SHLVL несколько интуитивно понятна: при запуске оболочки она проверяет, установлен ли SHLVL . Если он не установлен (или установлен на что-то отличное от числа), оболочка устанавливает его в 1. Если он установлен (в число), оболочка добавляет к нему 1.

Но по этой логике, если вы скажете exec sh , ваш SHLVL должен подняться. Но это нежелательно, потому что ваш реальный уровень оболочки не увеличился. Оболочка обрабатывает это, вычитая один из SHLVL когда вы выполняете exec :

 $ echo "$SHLVL" 1 $ set | grep SHLVL SHLVL=1 $ env | grep SHLVL SHLVL=1 $ (env | grep SHLVL) SHLVL=1 $ (env) | grep SHLVL SHLVL=1 $ (exec env) | grep SHLVL SHLVL=0 

Так

 vim() { ( ((SHLVL++)); exec vim "$@");} 

это мытье; он увеличивает SHLVL только для уменьшения его снова. Вы могли бы просто сказать vim , не используя функцию.

Заметка:
Согласно Stéphane Chazelas (кто знает все) , некоторые оболочки достаточно умны, чтобы этого не делать, если exec находится в подоболочке.

Чтобы исправить это, вы сделали бы

 vim() { ( ((SHLVL+=2)); exec vim "$@");} 

Затем я увидел, что вы хотите считать уровни vim независимо от уровней оболочки. Ну, точно такой же трюк работает (ну, с незначительной модификацией):

 vim() { ( ((SHLVL++, VILVL++)); export VILVL; exec vim "$@");} 

(и т. д. для vi , view и т. д.). export необходим, потому что VILVL по умолчанию не определен как переменная среды. Но он не должен быть частью функции; вы можете просто export VILVL как отдельную команду (в вашем .bashrc ). И, как обсуждалось выше, если дополнительный процесс оболочки не является проблемой для вас, вы можете выполнить command vim вместо exec vim и оставить только SHLVL :

 vim() { ( ((VILVL++)); command vim "$@");} 

Личное предпочтение:
Вы можете переименовать VILVL в нечто вроде VIM_LEVEL . Когда я смотрю на « VILVL », у меня болят глаза; они не могут сказать, является ли это орфографией «винил» или неправильной римской цифрой.


Если вы используете оболочку, которая не поддерживает SHLVL (например, тире), вы можете реализовать ее самостоятельно, пока оболочка реализует загрузочный файл. Просто сделай что-нибудь вроде

 if [ "$SHELL_LEVEL" = "" ] then SHELL_LEVEL=1 else SHELL_LEVEL=$(expr "$SHELL_LEVEL" + 1) fi export SHELL_LEVEL 

в вашем .profile или соответствующем файле. (Вероятно, вы не должны использовать имя SHLVL , так как это вызовет хаос, если вы когда-нибудь начнете использовать оболочку, поддерживающую SHLVL .)


В других ответах была затронута проблема внедрения значений переменных среды среды в приглашение оболочки, поэтому я не буду повторять это, особенно вы говорите, что уже знаете, как это сделать.

Вы можете рассчитывать столько раз, сколько нужно, чтобы подняться до дерева процессов, пока не найдете лидера сеанса. Как с zsh на Linux:

 lvl() { local n=0 pid=$$ buf until IFS= read -rd '' buf < /proc/$pid/stat set -- ${(s: :)buf##*\)} ((pid == $4)) do ((n++)) pid=$2 done echo $n } 

Или POSIXly (но менее эффективный):

 lvl() ( unset IFS pid=$$ n=0 until set -- $(ps -o ppid= -o sid= -p "$pid") [ "$pid" -eq "$2" ] do n=$((n + 1)) pid=$1 done echo "$n" ) 

Это даст 0 для оболочки, которая была запущена вашим эмулятором терминала или getty и еще одним для каждого потомка.

Вам нужно сделать это только один раз при запуске. Например:

 PS1="[$(lvl)]$PS1" 

в вашем ~/.zshrc или эквиваленте, чтобы он был в вашем приглашении.

tcsh и несколько других оболочек (по крайней мере, zsh , ksh93 , fish и bash ) поддерживают переменную $SHLVL которую они $SHLVL при запуске (и уменьшаются до запуска другой команды с exec (если только этот exec находится в подоболочке, если они не являются ошибками ( но многие из них))). Это только отслеживает количество вложенности оболочки, хотя и не вложенное в процесс. Также уровень 0 не является лидером сессии.

Используйте echo $SHLVL . Используйте принцип KISS . В зависимости от сложности вашей программы этого может быть достаточно.

Одним из возможных решений является просмотр вывода pstree . Когда вы запускаете внутри оболочки, которая была порождена из vi , часть дерева, в которой указывается pstree должна показать вам, насколько вы глубоки. Например:

 $ pstree <my-user-ID> ... ├─gnome-terminal-─┬─bash───vi───sh───vi───sh───pstree ... 

Первый вариант – только глубина раковины.

Простое решение для bash : добавьте в .bashrc следующие две строки (или измените текущее значение PS1 ):

 PS1="${SHLVL} \w\$ " export PS1 

Результат:

 1 ~$ bash 2 ~$ bash 3 ~$ exit exit 2 ~$ exit exit 1 ~$ 

Номер в начале строки подсказки будет обозначать уровень оболочки.

Второй вариант, с вложенными уровнями vim и shell.

добавьте эти строки в .bashrc

 branch=$(pstree -ls $$) vim_lvl=$(grep -o vim <<< "$branch" | wc -l) sh_lvl=$(grep -o bash <<< "$branch" | wc -l) PS1="v:${vim_lvl};s:$((sh_lvl - 1)):\w\$ " export PS1 

Результат:

 v:0;s:1:/etc$ bash v:0;s:2:/etc$ bash v:0;s:3:/etc$ vim ##### do ':sh' command in the vim, shell level is increasing by 1 v:1;s:4:/etc$ vim ##### do ':sh' command in the vim, shell level is increasing by 1 v:2;s:5:/etc$ bash v:2;s:6:/etc$ 

v: 1 – уровень глубины vim
s: 3 – уровень глубины оболочки

В вопросе вы упомянули разбор pstree . Вот относительно простой способ:

 bash-4.3$ pstree -Aals $$ | grep -E '^ *`-((|ba|da|k|c|tc|z)sh|vim?)( |$)' `-bash `-bash --posix `-vi -y `-dash `-vim testfile.txt `-tcsh `-csh `-sh - `-zsh `-bash --norc --verbose 

Параметры pstree :

  • -A – вывод ASCII для упрощения фильтрации (в нашем случае каждой команде предшествует `- )
  • -a – показать также аргументы команды, в качестве побочного эффекта каждая команда показана на отдельной строке, и мы можем легко фильтровать вывод с помощью grep
  • -l – не обрезать длинные строки
  • -s – показать родителям выбранного процесса
    (к сожалению, не поддерживается в старых версиях pstree )
  • $$ – выбранный процесс – PID текущей оболочки

Это не дает строгого ответа на этот вопрос, но во многих случаях это может сделать ненужным:

Когда вы впервые запускаете свою оболочку, запустите set -o ignoreeof . Не помещайте его в свой ~/.bashrc .

Сделайте привычкой набирать Ctrl-D, когда вы думаете, что находитесь в оболочке верхнего уровня и хотите быть уверенным.

Если вы не находитесь в оболочке верхнего уровня, Ctrl-D будет сигнализировать «конец ввода» текущей оболочке, и вы вернетесь на один уровень.

Если вы находитесь в оболочке верхнего уровня, вы получите сообщение:

 Use "logout" to leave the shell. 

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

  • как прокручивать несколько строк в завершении экрана zsh
  • Печать оцениваемых приглашающих заполнителей для отображения
  • zsh псевдоним переопределяется каким-то образом
  • Как запустить указанный код с помощью getopts, когда параметры или аргументы не заданы?
  • Изменение поведения завершения с расширением скобки в zsh
  • Как выполнить несколько команд вместе в фоновом режиме?
  • Как я могу достичь root после переключения с bash на zsh?
  • Изменение темы Zsh в Android Studio
  • ANDed условное использование regexp и переменных
  • Абсолютный путь к текущему zsh?
  • Список всех согласованных файлов, начиная с индекса
  • Interesting Posts

    Точка доступа (с hostapd) на том же интерфейсе, что и сеть / шлюз?

    переименование файлов в папке

    Опрос на сервере SFTP (лучший способ скопировать новые файлы с сервера SFTP на локальный компьютер через регулярные промежутки времени)

    Как я могу игнорировать «zip warning: name not match» при использовании команды zip с опцией -d?

    Где я могу поставить приватный ключ ssh?

    Что случилось с этой командой sed?

    команда telnet с пользовательской продолжительностью тайм-аута

    Что не так с моими заявлениями elif в этой игре с ножницами из каменной бумаги, которую я делаю

    Какое правильное определение FOSS?

    makehuman дает «ImportError: нет модуля с именем numpy»

    Как я могу получить список попыток входа в систему с помощью журналаctctl?

    Как я могу передать вывод программы или функции в переменную?

    Как извлечь неизвестные аргументы в сценарии оболочки?

    Сеть с Graylog в Qemu?

    Найти, когда жесткий диск был впервые установлен

    Linux и Unix - лучшая ОС в мире.