Il existe de nombreuses fonctions qui peuvent être utilisées dans le shell Bash. Leurs définitions peuvent être répertoriées par set
, mais comment trouver dans quels fichiers certaines fonctions définies par l'utilisateur sont définies?
Il existe de nombreuses fonctions qui peuvent être utilisées dans le shell Bash. Leurs définitions peuvent être répertoriées par set
, mais comment trouver dans quels fichiers certaines fonctions définies par l'utilisateur sont définies?
Réponses:
Activez le débogage. Du manuel Bash :
extdebug
Si défini à l'invocation du shell, ou dans un fichier de démarrage du shell, organisez l'exécution du profil de débogage avant le démarrage du shell, identique à l'
--debugger
option. S'il est défini après l'invocation, le comportement destiné à être utilisé par les débogueurs est activé:
- L'
-F
option de la fonctiondeclare
intégrée (voir Bash Builtins ) affiche le nom du fichier source et le numéro de ligne correspondant à chaque nom de fonction fourni en argument.
Exemple:
$ bash --debugger
$ declare -Ff quote
quote 143 /usr/share/bash-completion/bash_completion
Et en effet:
$ nl -ba /usr/share/bash-completion/bash_completion | sed -n 143,150p
143 quote()
144 {
145 local quoted=${1//\'/\'\\\'\'}
146 printf "'%s'" "$quoted"
147 }
148
149 # @see _quote_readline_by_ref()
150 quote_readline()
shopt -s extdebug; declare -Ff quote; shopt -u extdebug
.
find_function()( shopt -s extdebug; declare -F "$@"; )
. Avec les parens sur le corps de la fonction, il est exécuté dans un sous-shell et le changement de shopts n'affecte pas l'appelant. Et -f
cela ne semble pas nécessaire.
C'est en fait plus compliqué qu'il n'y paraît au premier abord. Les fichiers lus par votre shell dépendent du type de shell que vous utilisez actuellement. Qu'il soit interactif ou non, qu'il s'agisse d'un shell de connexion ou non, et quelle combinaison des éléments ci-dessus. Pour rechercher dans tous les fichiers par défaut qui peuvent être lus par les différents shells, vous pouvez faire (changer $functionName
le nom réel de la fonction que vous recherchez):
grep "$functionName" ~/.bashrc ~/.profile ~/.bash_profile ~/.bash.login \
~/.bash_aliases /etc/bash.bashrc /etc/profile \
/etc/profile.d/* /etc/environment 2> /dev/null
Si cela ne fonctionne pas, vous appelez peut-être un fichier non par défaut à l'aide de .
ou de son alias source
. Pour rechercher de tels cas, exécutez:
grep -P '(^|\s)(\.|source)\s+' ~/.bashrc ~/.profile ~/.bash_profile \
~/.bash.login ~/.bash_aliases /etc/bash.bashrc \
/etc/profile /etc/profile.d/* /etc/environment 2> /dev/null
Cela nécessite probablement quelques explications. Le -P
permet Perl Compatible Regular Expressions (PCRE) qui nous permet d'utiliser une syntaxe regex plus sophistiquée. Plus précisément:
(^|\s)
: correspond au début d'une ligne ( ^
) ou d'un espace ( \s
).(\.|source)\s+
: correspond soit à un .
caractère littéral ( \.
) soit au mot source
, mais uniquement s'ils sont suivis par un ou plusieurs espaces.Voici ce que cela me donne sur mon système:
$ grep -P '(^|\s)(\.|source)\s+' ~/.bashrc ~/.profile ~/.bash_profile \
> ~/.bash.login ~/.bash_aliases /etc/bash.bashrc \
> /etc/profile /etc/profile.d/* /etc/environment 2> /dev/null
/home/terdon/.bashrc: . /etc/bashrc
/home/terdon/.bashrc: . /etc/bash_completion
/home/terdon/.bashrc:. $HOME/scripts/git-prompt.sh
/home/terdon/.bashrc:# echo -n "$n : "; grep "^CA" $n |perl -e 'my ($a,$c)=0; while(<>){$c++;next if /cellular_component_unknown/; next if /biological_process/; $a++} print "$a Classes of $c annotated (" . $a*100/$c . ")\n"'
/etc/bash.bashrc:[ -r /usr/share/bash-completion/bash_completion ] && . /usr/share/bash-completion/bash_completion
/etc/profile: test -r "$profile" && . "$profile"
/etc/profile: . /etc/bash.bashrc
/etc/profile.d/locale.sh: . "$XDG_CONFIG_HOME/locale.conf"
/etc/profile.d/locale.sh: . "$HOME/.config/locale.conf"
/etc/profile.d/locale.sh: . /etc/locale.conf
/etc/profile.d/Z97-byobu.sh: . /usr/bin/byobu-launch
/etc/profile.d/Z97-byobu.sh: . /usr/bin/byobu-launch
/etc/profile.d/Z97-byobu.sh: . /usr/bin/byobu-launch
/etc/profile.d/Z97-byobu.sh: . /usr/bin/byobu-launch
/etc/profile.d/Z97-byobu.sh: . /usr/bin/byobu-launch
Comme vous pouvez le voir, cependant, cela imprimera toute la ligne correspondante. Ce qui nous intéresse vraiment, c'est la liste des noms de fichiers appelés, pas la ligne qui les appelle. Vous pouvez les obtenir avec ce regex plus compliqué:
grep -hPo '(^|\s)(\.|source)\s+\K\S+' ~/.bashrc ~/.profile ~/.bash_profile \
~/.bash.login ~/.bash_aliases \
/etc/bash.bashrc /etc/profile \
/etc/profile.d/* /etc/environment 2> /dev/null
L' -h
indicateur supprime l'impression des noms de fichiers où une correspondance a été trouvée, ce qui est grep
fait par défaut lorsqu'on lui demande de rechercher dans plusieurs fichiers. Le -o
moyen "n'imprime que la partie correspondante de la ligne". Les éléments supplémentaires ajoutés à l'expression régulière sont les suivants:
\K
: ignorer tout ce qui correspond à ce point. Il s'agit d'une astuce PCRE qui vous permet d'utiliser une expression rationnelle complexe pour trouver votre correspondance, mais pas d'inclure cette partie correspondante lors de l'utilisation du -o
drapeau de grep .Sur mon système, la commande ci-dessus renverra:
$ grep -hPo '(^|\s)(\.|source)\s+\K\S+' ~/.bashrc ~/.profile ~/.bash_profile \
> ~/.bash.login ~/.bash_aliases \
> /etc/bash.bashrc /etc/profile \
> /etc/profile.d/* /etc/environment 2> /dev/null
/etc/bashrc
/etc/bash_completion
$HOME/scripts/git-prompt.sh
$a*100/$c
")\n"'
/usr/share/bash-completion/bash_completion
"$profile"
/etc/bash.bashrc
"$XDG_CONFIG_HOME/locale.conf"
"$HOME/.config/locale.conf"
/etc/locale.conf
/usr/bin/byobu-launch
/usr/bin/byobu-launch
/usr/bin/byobu-launch
/usr/bin/byobu-launch
/usr/bin/byobu-launch
Notez que j'ai une utilisation de .
suivie d'un espace qui n'est pas utilisé pour le sourcing mais c'est parce que j'ai un alias qui appelle une autre langue, pas bash. C'est ce qui donne l'étrange $a*100/$c
et ")\n"'
dans la sortie ci-dessus. Mais cela peut être ignoré.
Enfin, voici comment rassembler tout cela et rechercher un nom de fonction dans tous les fichiers par défaut et tous les fichiers que vos fichiers par défaut proviennent:
grep_function(){
target="$@"
files=( ~/.bashrc ~/.profile ~/.bash_profile ~/.bash.login
~/.bash_aliases /etc/bash.bashrc /etc/profile
/etc/profile.d/* /etc/environment)
while IFS= read -r file; do
files+=( "$file" )
done < <(grep -hPo '(^|\s)(\.|source)\s+\K\S+' "${files[@]}" 2>/dev/null)
for file in "${files[@]}"; do
## The tilde of ~/ can break this
file=$(sed 's|~/|'"$HOME"'/|g' <<<"$file")
if [[ -e $file ]]; then
grep -H "$target" -- "$file"
fi
done
}
Ajoutez ces lignes à votre ~/.bashrc
et vous pouvez ensuite exécuter (j'utilise fooBar
comme exemple de nom de fonction):
grep_function fooBar
Par exemple, si j'ai cette ligne dans mon ~/.bashrc
:
. ~/a
Et le fichier ~/a
est:
$ cat ~/a
fooBar(){
echo foo
}
Je devrais le trouver avec:
$ grep_function fooBar
/home/terdon/a:fooBar(){
+=
array+="foo"
ajout de la chaîne foo
au 1er élément du tableau?
Le fichier dotfile habituel par utilisateur bash
est ~/.bashrc
. Cependant, il peut très bien source d'autres fichiers, j'aime par exemple garder les alias et les fonctions dans des fichiers séparés appelés ~/.bash_aliases
et ~/.bash_functions
, ce qui facilite leur recherche. Vous pouvez rechercher .bashrc
des source
commandes avec:
grep -E '(^\s*|\s)(\.|source)\s' /home/USERNAME/.bashrc
Une fois que vous avez la liste des fichiers créés par l'utilisateur, vous pouvez les rechercher ainsi que l'utilisateur .bashrc
avec un seul grep
appel, par exemple pour la fonction foo
pour ma configuration:
grep foo /home/USERNAME/.bash{rc,_aliases,_functions}