Como posso encontrar onde determinada função bash está definida?
772
Existem muitas funções que podem ser usadas no shell Bash. Suas definições podem ser listadas por set, mas como descobrir em quais arquivos certas funções definidas pelo usuário estão definidas?
Se definido na chamada do shell ou em um arquivo de inicialização do shell, providencie a execução do perfil do depurador antes do início do shell, idêntico à
--debuggeropção. Se definido após a chamada, o comportamento destinado ao uso por depuradores é ativado:
A -Fopção para o declarebuiltin (consulte Bash Builtins ) exibe o nome do arquivo de origem e o número da linha correspondente a cada nome de função fornecido como um argumento.
Na verdade, isso é mais complicado do que parece à primeira vista. Quais arquivos são lidos pelo seu shell depende do tipo de shell que você está executando no momento. Se é interativo ou não, se é um shell de login ou não e qual combinação dos itens acima. Para pesquisar todos os arquivos padrão que podem ser lidos pelos diferentes shells, você pode fazer (mude $functionNamepara o nome real da função que está procurando):
Isso provavelmente precisa de alguma explicação. O -Phabilita Expressões Regulares Compatíveis com Perl (PCRE) que nos permite usar uma sintaxe de regex mais sofisticada. Especificamente:
(^|\s): corresponde ao início de uma linha ( ^) ou espaço em branco ( \s).
(\.|source)\s+: correspondem a um caractere literal .( \.) ou à palavra source, mas somente se forem seguidos por um ou mais caracteres de espaço em branco.
Como você pode ver, no entanto, isso imprimirá toda a linha correspondente. O que realmente nos interessa é a lista de nomes de arquivos chamados, não a linha que os está chamando. Você pode obtê-los com este regex mais complicado:
O -hsinalizador suprime a impressão dos nomes de arquivo onde uma correspondência foi encontrada, o que grepocorre por padrão quando solicitado a pesquisar em vários arquivos. Os -omeios "imprimem apenas a parte correspondente da linha". As coisas extras adicionadas ao regex são:
\K: ignore qualquer coisa correspondente até este ponto. Este é um truque de PCRE que permite usar um regex complexo para encontrar sua correspondência, mas não inclui a parte correspondente ao usar o -osinalizador do grep.
Observe que tenho um uso de .seguido por um espaço que não é usado para sourcing, mas é porque tenho um alias que está chamando outro idioma, não o bash. É isso que dá estranho $a*100/$ce ")\n"'na saída acima. Mas isso pode ser ignorado.
Por fim, veja como juntar tudo isso e procurar um nome de função em todos os arquivos padrão e em todos os arquivos que seus arquivos padrão estão fornecendo:
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
}
Adicione essas linhas ao seu ~/.bashrce você poderá executar (estou usando fooBarcomo exemplo o nome da função):
grep_function fooBar
Por exemplo, se eu tiver esta linha no meu ~/.bashrc:
As leituras usuais de dotfile por usuário bashsão ~/.bashrc. No entanto, pode muito bem originar outros arquivos, por exemplo, gosto de manter aliases e funções em arquivos separados chamados ~/.bash_aliasese ~/.bash_functions, o que torna muito mais fácil encontrá-los. Você pode pesquisar os .bashrccomandos sourcecom:
Depois de ter a lista de arquivos criados pelo usuário, você pode pesquisá-los e os do usuário .bashrccom uma única grepchamada, por exemplo, para função foopara minha configuração:
Ligue a depuração. Do manual do Bash :
Exemplo:
E realmente:
Na verdade, isso é mais complicado do que parece à primeira vista. Quais arquivos são lidos pelo seu shell depende do tipo de shell que você está executando no momento. Se é interativo ou não, se é um shell de login ou não e qual combinação dos itens acima. Para pesquisar todos os arquivos padrão que podem ser lidos pelos diferentes shells, você pode fazer (mude
$functionName
para o nome real da função que está procurando):Se isso não funcionar, você pode estar chamando um arquivo não padrão usando
.
ou seu aliassource
. Para encontrar esses casos, execute:Isso provavelmente precisa de alguma explicação. O
-P
habilita Expressões Regulares Compatíveis com Perl (PCRE) que nos permite usar uma sintaxe de regex mais sofisticada. Especificamente:(^|\s)
: corresponde ao início de uma linha (^
) ou espaço em branco (\s
).(\.|source)\s+
: correspondem a um caractere literal.
(\.
) ou à palavrasource
, mas somente se forem seguidos por um ou mais caracteres de espaço em branco.Aqui está o que isso me dá no meu sistema:
Como você pode ver, no entanto, isso imprimirá toda a linha correspondente. O que realmente nos interessa é a lista de nomes de arquivos chamados, não a linha que os está chamando. Você pode obtê-los com este regex mais complicado:
O
-h
sinalizador suprime a impressão dos nomes de arquivo onde uma correspondência foi encontrada, o quegrep
ocorre por padrão quando solicitado a pesquisar em vários arquivos. Os-o
meios "imprimem apenas a parte correspondente da linha". As coisas extras adicionadas ao regex são:\K
: ignore qualquer coisa correspondente até este ponto. Este é um truque de PCRE que permite usar um regex complexo para encontrar sua correspondência, mas não inclui a parte correspondente ao usar o-o
sinalizador do grep.No meu sistema, o comando acima retornará:
Observe que tenho um uso de
.
seguido por um espaço que não é usado para sourcing, mas é porque tenho um alias que está chamando outro idioma, não o bash. É isso que dá estranho$a*100/$c
e")\n"'
na saída acima. Mas isso pode ser ignorado.Por fim, veja como juntar tudo isso e procurar um nome de função em todos os arquivos padrão e em todos os arquivos que seus arquivos padrão estão fornecendo:
Adicione essas linhas ao seu
~/.bashrc
e você poderá executar (estou usandofooBar
como exemplo o nome da função):Por exemplo, se eu tiver esta linha no meu
~/.bashrc
:E o arquivo
~/a
é:Eu deveria encontrá-lo com:
As leituras usuais de dotfile por usuário
bash
são~/.bashrc
. No entanto, pode muito bem originar outros arquivos, por exemplo, gosto de manter aliases e funções em arquivos separados chamados~/.bash_aliases
e~/.bash_functions
, o que torna muito mais fácil encontrá-los. Você pode pesquisar os.bashrc
comandossource
com:Depois de ter a lista de arquivos criados pelo usuário, você pode pesquisá-los e os do usuário
.bashrc
com uma únicagrep
chamada, por exemplo, para funçãofoo
para minha configuração: