Как найти файл, в котором определена функция bash?

33

Я не могу понять, как найти файл, в котором определена функция bash ( __git_ps1в моем случае).

Я экспериментировал с declare, type, which, но ничего не говорит мне исходный файл. Я где-то читал, что declareможно напечатать имя файла и номер строки, но не было объяснено как. helpСтраница declareне говорит , это тоже.

Как я могу получить эту информацию?

Алексей
источник
Если путь к файлу функции не включен $PATH, то typeработать не будет. Вы можете попробовать просто использовать findили locate. locateбудет намного быстрее, так как он использует уже существующую базу данных, но не будет работать, если команда была установлена ​​совсем недавно.
user628544
Связанный: unix.stackexchange.com/q/322459/117549
Джефф Шаллер

Ответы:

37

Если вы готовы к запуску функции, то вы можете получить информацию, используя set -xдля отслеживания выполнения и установки PS4переменной.

  1. Запустите bash --debuggerили используйте shopt -s extdebugдля записи дополнительной отладочной информации.

  2. Установите PS4«подсказку», напечатанную при трассировке, чтобы показать исходную строку.

  3. Включите трассировку.

  4. Затем вы можете запустить свою функцию, и для каждой строки вы получите имя файла функции.

  5. используйте, set +xчтобы отключить трассировку.

Так что для этого случая вы бы запустить

bash --debugger
PS4='+ ${BASH_SOURCE[0]} '
set -x ; __git_ps1 ; set +x
Икар
источник
«-x После развертывания каждой простой команды, для команды, команды case, команды select или арифметики для команды, отобразите расширенное значение PS4, затем команду и ее расширенные аргументы или связанный список слов». Ницца!
10
25

Если вы не желаете запускать функцию, вы все равно можете настроить отладку и получить информацию. Шаги

  1. начать bash --debuggerили shopt -s extdebugдо того, как функция будет определена.
  2. declare -F __git_ps1

и он сообщит, где определена функция.

Преимущества этого метода по сравнению с просмотром аннотированной трассировки выполнения в PS4

  • Много меньше выходной
  • Это прямо отвечает на вопрос

Преимущества трассировки исполнения

  • Просмотреть все вызываемые функции одновременно
  • Смотрите отношения между вызываемыми функциями
  • Посмотреть рекурсию

Я настоятельно рекомендую иметь shopt -s extdebugв начале оба файла~/.bashrc и ~/.bash_profileпокрывать разные файлы, используемые в разных случаях Invocation .

Икар
источник
1
Это также работает, если shopt -s extdebugвызывается после определения функции. Осторожно, номера строк могут быть отключены (текущая ошибка), если функция объявлена ​​через eval.
Стефан
Я был после ошибочного завершения для vpnc. После того, как bash --debuggerмне пришлось фактически запустить завершение, чтобы получить определенную функцию завершения и сообщить о ней declare -F _vpnc.
Харальд
У меня нет ~/.bash_profileв Xubuntu 18.04.
Ярно
Почему вы настоятельно рекомендуете shopt -s extdebugустановить по умолчанию?
Ярно
@jarno Смотрите страницу руководства, но она позволяет вам видеть эту информацию, позволяет унаследовать ловушки DEBUG и, насколько я вижу, не имеет недостатков. Смотрите ссылку для альтернативы ~ / .bash_profile или просто создайте ее.
Икар
9

Отличное решение @ icarus работает для функций, если они определены буквально, а не как результат evalсодержимого другого файла (в котором файл с символом evalбудет отображаться как источник). Он не будет печатать исходный файл с псевдонимами, встроенными модулями оболочки (например echo) и исполняемыми файлами (двоичными или нет), и я считаю, что эта информация вообще недоступна. Некоторые команды могут печатать свои исходные файлы (и даже могут быть правдивыми об этом), либо в ходе обычного выполнения, либо в ответ на сигнал.

__git_ps1определяется в моей системе Arch Linux /usr/share/git/git-prompt.shи /usr/share/git/completion/git-prompt.shв моей системе, поэтому она может быть одинаковой для вас.

Взгляните на раздел « Вызов », man bashесли вы хотите найти команды, специально созданные в начале оболочки - они могут получать другие файлы, которые, в свою очередь, являются источником других файлов.

l0b0
источник
Можно ли получить список файлов, которые получены при запуске bash?
pfnuesel
@pfnuesel - решать только вам. Значения по умолчанию в $HOME/.bashrcи в $HOME/.profile. См. Linuxfromscratch.org/blfs/view/svn/postlfs/profile.html, который объясняет некоторые детали того, когда и как каждый файл получен.
Джо
2
@Joe gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html гораздо лучше ссылки. /etc/profile, $HOME/.bash_profile, $HOME/.bash_login, И содержание $ENVи $BASH_ENVнеобходимость быть добавлены в список.
Икар
@icarus - Спасибо. Это лучшее объяснение.
Джо
8

Кажется, что это невозможно bash, но это zsh:

$ type __git_ps1
> __git_ps1 is a shell function from /usr/share/git/git-prompt.sh
pfnuesel
источник
Вопрос уточняет Баш ...
Джефф Шаллер
4
@JeffSchaller: очевидный способ использовать этот ответ - настроить zsh на источник тех же файлов, что и bash, а затем использовать его, чтобы найти определение. В этом ответе не предлагается переход на zsh, просто очевидно, что это полезный инструмент, который понимает синтаксис оболочки лучше, чем универсальные инструменты, такие как find/ locate/ grep.
Питер Кордес
Тогда я бы сказал, @PeterCordes, что этот ответ в настоящее время не делает того, что вы говорите, он должен делать, чтобы ответить на Вопрос. Я не знаю, читает ли zsh те же файлы, что и bash.
Джефф Шаллер
@JeffSchaller: Согласен, этот ответ нуждается в улучшении. zsh почти наверняка не читает те же ~/.whateverфайлы, что и bash по умолчанию, и даст только полезные ответы для функций, определенных в общих местах, как в этом случае, которые не были переопределены ~/.bashrcили что-то еще.
Питер Кордес
-1

Объявите функцию с тем же именем и установите ее только для чтения как можно раньше, затем активируйте режим xtrace, например:

__git_ps1(){ :;}
readonly -f __git_ps1
set -x

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

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

woodengod
источник
-3

Ты пробовал это?

grep -rnw '/path/to/somewhere/' -e "pattern" 

или любую другую команду, найденную здесь:

Как найти все файлы, содержащие определенный текст в Linux? | Переполнение стека

Кажется, мне нужно дать вам больше объяснений. Ваш вопрос спрашивает "" Таким образом, если вы выполните следующую команду, она должна вернуть все файлы, в которых определена функция bash.

grep -rnw 'Path2Search' -e "#!/bin/bash"

BASH Программирование - Функции | Проект документации Linux

RadFox
источник
1
Ссылка только на ответы абсолютно не приветствуется. Пожалуйста, добавьте некоторые объяснения.
Heemayl