Comment trouver le fichier où une fonction bash est définie?

33

Je ne peux pas comprendre comment trouver le fichier où une fonction bash est définie ( __git_ps1dans mon cas).

J'ai expérimenté avec declare, type, whichmais rien ne me dit que le fichier source. J'ai lu quelque part qui declarepeut imprimer le nom du fichier et le numéro de ligne, mais il n'a pas été expliqué comment. La helppage pour declarene le dit pas non plus.

Comment puis-je obtenir ces informations?

Alexey
la source
Si le chemin d'accès au fichier de la fonction n'est pas inclus dans $PATH, typecela ne fonctionnera pas. Vous pouvez essayer d'utiliser simplement findou locate. locatesera beaucoup plus rapide, car il utilise une base de données préexistante, mais cela ne fonctionnera pas si la commande a été installée récemment.
user628544

Réponses:

37

Si vous êtes prêt à exécuter la fonction, vous pouvez obtenir les informations en utilisant set -xpour tracer l'exécution et en définissant la PS4variable.

  1. Démarrez bash avec --debuggerou sinon utilisez shopt -s extdebugpour enregistrer des informations de débogage supplémentaires.

  2. Définissez PS4, l '«invite» imprimée lors du traçage pour afficher la ligne source.

  3. Activez le traçage.

  4. vous pouvez ensuite exécuter votre fonction et pour chaque ligne, vous obtiendrez le nom de fichier de la fonction.

  5. utiliser set +xpour désactiver le traçage.

Donc, dans ce cas, vous courriez

bash --debugger
PS4='+ ${BASH_SOURCE[0]} '
set -x ; __git_ps1 ; set +x
icarus
la source
"-x Après avoir développé chaque commande simple, pour une commande, une commande de casse, une commande de sélection ou une arithmétique pour une commande, affichez la valeur développée de PS4, suivie de la commande et de ses arguments développés ou de la liste de mots associée." Agréable!
l0b0
25

Si vous ne souhaitez pas exécuter la fonction, vous pouvez toujours configurer le débogage et obtenir les informations. Les étapes sont

  1. démarrer bash --debuggerou shopt -s extdebugavant que la fonction ne soit définie.
  2. declare -F __git_ps1

et il indiquera où la fonction est définie.

Les avantages de cette méthode par rapport à la visualisation de la trace d'exécution annotée avec PS4 sont les suivants:

  • Beaucoup moins de sortie
  • Il répond directement à la question

Les avantages de la trace d'exécution sont

  • Voir toutes les fonctions appelées à la fois
  • Voir les relations entre les fonctions appelées
  • Voir récursivité

Je recommande fortement d' avoir shopt -s extdebugau début des deux ~/.bashrcet ~/.bash_profilede couvrir les différents fichiers utilisés dans différents cas d' invocation .

icarus
la source
1
Il fonctionne également si shopt -s extdebugest appelé après la définition de la fonction. Méfiez-vous des numéros de ligne peut être désactivé (un bug actuel) si la fonction est déclarée à travers eval.
Stéphane Chazelas
J'étais après un achèvement malavisé pour vpnc. Après, bash --debuggerje devais réellement déclencher l'achèvement pour obtenir la fonction d'achèvement définie et obtenir son rapport declare -F _vpnc.
Harald
Je n'ai pas ~/.bash_profiledans Xubuntu 18.04.
jarno Il y a
Pourquoi recommandez -vous fortement d' avoir shopt -s extdebugdéfini la valeur par défaut?
jarno Il y a
@jarno Voir la page de manuel, mais elle vous permet de voir ces informations, permet aux pièges DEBUG d'être hérités et n'a aucun inconvénient pour autant que je puisse voir. Voir le lien pour des alternatives à ~ / .bash_profile ou simplement le créer.
icarus il y a
9

La grande solution de @ icarus fonctionne pour les fonctions, tant qu'elles sont définies littéralement et non pas le résultat d'un evaldu contenu d'un autre fichier (dans lequel le fichier avec le evalapparaîtra comme source). Il n'imprimera pas le fichier source des alias, des shell intégrés (comme echo) et des exécutables (binaires ou non), et je pense que ces informations ne sont pas disponibles en général. Certaines commandes peuvent imprimer leurs fichiers source (et peuvent même être véridiques à ce sujet), soit au cours d'une exécution normale, soit en réponse à un signal.

__git_ps1est défini dans /usr/share/git/git-prompt.shet /usr/share/git/completion/git-prompt.shsur mon système, Arch Linux, il peut donc en être de même pour vous.

Jetez un oeil à la section Invocation de man bashsi vous voulez rechercher des commandes spécifiquement fournies au début du shell - elles peuvent source d'autres fichiers qui à leur tour source d'autres fichiers.

l0b0
la source
Peut-on obtenir une liste des fichiers provenant du démarrage bash?
pfnuesel
@pfnuesel - c'est à vous. Les valeurs par défaut sont in $HOME/.bashrcet in $HOME/.profile. Voir: linuxfromscratch.org/blfs/view/svn/postlfs/profile.html qui explique certains détails sur quand et comment chaque fichier est obtenu.
Joe
2
@Joe gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html est une bien meilleure référence. /etc/profile, $HOME/.bash_profile, $HOME/.bash_login, Et le contenu $ENVet $BASH_ENVdoivent être ajoutés à votre liste.
icarus
@icarus - Merci. C'est une meilleure explication.
Joe
8

Cela ne semble pas possible en bash, mais c'est en zsh:

$ type __git_ps1
> __git_ps1 is a shell function from /usr/share/git/git-prompt.sh
pfnuesel
la source
La question spécifie bash ...
Jeff Schaller
4
@JeffSchaller: La façon évidente d'utiliser cette réponse est de configurer zsh pour générer les mêmes fichiers que bash, puis de l'utiliser pour trouver la définition. Cette réponse ne suggère pas de passer à zsh, juste que c'est évidemment un outil utile qui comprend mieux la syntaxe du shell que les outils génériques comme find/ locate/ grep.
Peter Cordes
Je dirais donc, @PeterCordes, que cette réponse ne fait actuellement pas ce que vous dites qu'elle devrait faire pour répondre à la question. Je ne sais pas si zsh lit nativement les mêmes fichiers que bash.
Jeff Schaller
@JeffSchaller: D'accord, cette réponse doit être améliorée. zsh ne lit presque certainement pas les mêmes ~/.whateverfichiers que bash par défaut, et ne donnera des réponses utiles que pour les fonctions définies dans des emplacements partagés comme dans ce cas, qui ne sont pas redéfinis dans ~/.bashrcou autre.
Peter Cordes
-1

Déclarez une fonction du même nom et définissez-la en lecture seule le plus tôt possible, puis activez le mode xtrace, quelque chose comme:

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

Après cela, lorsque vous vous connecterez, vous verrez des informations de trace qui incluent le sourcing des fichiers. Au moment où il y a une tentative de déclaration de la fonction en lecture seule existante, vous verrez un message d'erreur. Le dernier fichier source avant il doit contenir la déclaration que vous recherchez.

Vous devrez peut-être mettre cela dans le profil bash du système. N'oubliez pas non plus de revenir sur les modifications après avoir trouvé le coupable.

woodengod
la source
-3

Avez-vous essayé cela?

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

ou l'une des autres commandes trouvées ici:

Comment trouver tous les fichiers contenant du texte spécifique sous Linux? | Débordement de pile

Il semble que je doive vous donner plus d'explications. Votre question demande "" Ainsi, si vous exécutez la commande suivante, elle devrait renvoyer tous les fichiers où une fonction bash est définie.

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

Programmation BASH - Fonctions | Projet de documentation Linux

RadFox
la source
1
Les réponses de lien uniquement ne sont absolument pas encouragées. Veuillez ajouter quelques explications.
heemayl