Respuestas:
Activa la depuración. Del manual de Bash :
extdebug
Si se establece en la invocación del shell, o en un archivo de inicio del shell, organice la ejecución del perfil del depurador antes de que se inicie el shell, idéntico a la
--debugger
opción. Si se establece después de la invocación, se habilita el comportamiento destinado a ser utilizado por los depuradores:
- La
-F
opción para eldeclare
builtin (ver Bash Builtins ) muestra el nombre del archivo fuente y el número de línea correspondiente a cada nombre de función proporcionado como argumento.
Ejemplo:
$ bash --debugger
$ declare -Ff quote
quote 143 /usr/share/bash-completion/bash_completion
Y de hecho:
$ 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 "$@"; )
. Con los parens en el cuerpo de la función, se ejecuta en una subshell y el cambio a shopts no afecta a la persona que llama. Y el -f
no parece ser necesario.
Esto es realmente más complicado de lo que parece al principio. Los archivos que lee su shell dependen del tipo de shell que esté ejecutando actualmente. Si es interactivo o no, si se trata de un shell de inicio de sesión o no, y qué combinación de lo anterior. Para buscar en todos los archivos predeterminados que pueden leer los diferentes shells, puede hacer (cambiar $functionName
el nombre real de la función que está buscando):
grep "$functionName" ~/.bashrc ~/.profile ~/.bash_profile ~/.bash.login \
~/.bash_aliases /etc/bash.bashrc /etc/profile \
/etc/profile.d/* /etc/environment 2> /dev/null
Si eso no funciona, puede estar llamando a un archivo no predeterminado usando .
o su alias source
. Para encontrar estos casos, ejecute:
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
Eso probablemente necesita alguna explicación. El -P
permite Perl Compatible Regular Expressions (PCRE), que vamos a utilizar una sintaxis de expresiones regulares más elegante. Específicamente:
(^|\s)
: coincide con el comienzo de una línea ( ^
) o un espacio en blanco ( \s
).(\.|source)\s+
: coincide con un .
carácter literal ( \.
) o la palabra source
, pero solo si van seguidos de uno o más espacios en blanco.Esto es lo que me da en mi sistema:
$ 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
Como puede ver, sin embargo, esto imprimirá toda la línea coincidente. Lo que realmente nos interesa es la lista de nombres de archivos llamados, no la línea que los llama. Puede obtener aquellos con esto, más complicado, regex:
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
La -h
bandera suprime la impresión de los nombres de los archivos donde se encontró una coincidencia, lo que grep
ocurre de manera predeterminada cuando se le pide que busque en varios archivos. Los -o
medios "solo imprimen la parte correspondiente de la línea". Las cosas adicionales agregadas a la expresión regular son:
\K
: ignora todo lo que coincida hasta este punto. Este es un truco PCRE que le permite usar una expresión regular compleja para encontrar su coincidencia, pero no incluye esa parte coincidente cuando se usa la -o
bandera de grep .En mi sistema, el comando anterior devolverá:
$ 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
Tenga en cuenta que tengo un uso .
seguido de un espacio que no se usa para el abastecimiento, pero eso es porque tengo un alias que llama a otro idioma, no bash. Eso es lo que da lo extraño $a*100/$c
y ")\n"'
en la salida anterior. Pero eso puede ser ignorado.
Finalmente, aquí se explica cómo juntar todo eso y buscar el nombre de una función en todos los archivos predeterminados y todos los archivos de los que provienen sus archivos predeterminados:
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
}
Agregue esas líneas a su ~/.bashrc
y luego puede ejecutar (estoy usando fooBar
como un nombre de función de ejemplo):
grep_function fooBar
Por ejemplo, si tengo esta línea en mi ~/.bashrc
:
. ~/a
Y el archivo ~/a
es:
$ cat ~/a
fooBar(){
echo foo
}
Debería encontrarlo con:
$ grep_function fooBar
/home/terdon/a:fooBar(){
+=
array+="foo"
agregar la cadena foo
al primer elemento de la matriz?
La lectura habitual de archivos de puntos por usuario bash
es ~/.bashrc
. Sin embargo, puede muy bien obtener otros archivos, por ejemplo, me gusta mantener los alias y las funciones en archivos separados llamados ~/.bash_aliases
y ~/.bash_functions
, lo que hace que sea mucho más fácil encontrarlos. Puede buscar en el .bashrc
de source
comandos con:
grep -E '(^\s*|\s)(\.|source)\s' /home/USERNAME/.bashrc
Una vez que tenga la lista de archivos creados por el usuario, puede buscarlos y al usuario .bashrc
con una sola grep
llamada, por ejemplo, para la función foo
de mi configuración:
grep foo /home/USERNAME/.bash{rc,_aliases,_functions}