Risposte:
Attiva il debug. Dal manuale di Bash :
extdebug
Se impostato su invocazione della shell o in un file di avvio della shell, provvedere all'esecuzione del profilo di debugger prima dell'avvio della shell, identico
--debugger
all'opzione. Se impostato dopo l'invocazione, il comportamento destinato all'uso da parte dei debugger è abilitato:
- L'
-F
opzione per ildeclare
builtin (vedere Bash Builtins ) visualizza il nome del file di origine e il numero di riga corrispondente a ciascun nome di funzione fornito come argomento.
Esempio:
$ bash --debugger
$ declare -Ff quote
quote 143 /usr/share/bash-completion/bash_completion
E senza dubbio:
$ 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 le parentesi nel corpo della funzione, viene eseguita in una sottostruttura e la modifica a shopts non influisce sul chiamante. E il -f
non sembra essere necessario.
Questo è in realtà più complicato di quanto sembri inizialmente. I file letti dalla shell dipendono dal tipo di shell attualmente in esecuzione. Che sia interattivo o no, che si tratti di una shell di accesso o non di accesso e quale combinazione di quanto sopra. Per cercare tra tutti i file predefiniti che possono essere letti dalle diverse shell, è possibile eseguire (passare $functionName
al nome effettivo della funzione che si sta cercando):
grep "$functionName" ~/.bashrc ~/.profile ~/.bash_profile ~/.bash.login \
~/.bash_aliases /etc/bash.bashrc /etc/profile \
/etc/profile.d/* /etc/environment 2> /dev/null
Se il problema persiste, è possibile che si stia chiamando un file non predefinito utilizzando .
o il suo alias source
. Per trovare tali casi, eseguire:
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
Questo probabilmente ha bisogno di qualche spiegazione. Il -P
permette Perl Compatible Regular Expressions (PCRE), che cerchiamo di utilizzare una sintassi regex più elaborato. In particolare:
(^|\s)
: corrisponde all'inizio di una riga ( ^
) o uno spazio bianco ( \s
).(\.|source)\s+
: corrisponde a un .
carattere letterale ( \.
) o alla parola source
, ma solo se sono seguiti da uno o più caratteri bianchi.Ecco cosa mi dà sul mio 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
Come puoi vedere, tuttavia, questo stamperà l'intera linea abbinata. Ciò a cui siamo veramente interessati è l'elenco dei nomi dei file chiamati, non la linea che li chiama. Puoi ottenere quelli con questo, più complicato, 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
Il -h
flag sopprime la stampa dei nomi dei file in cui è stata trovata una corrispondenza, che grep
per impostazione predefinita viene eseguita quando viene richiesto di cercare tra più file. Il -o
mezzo "stampa solo la parte corrispondente della riga". Le cose extra aggiunte al regex sono:
\K
: ignora tutto ciò che corrisponde a questo punto. Questo è un trucco di PCRE che ti consente di usare una regex complessa per trovare la tua corrispondenza ma non includere quella porzione corrispondente quando usi la -o
bandiera di grep .Sul mio sistema, il comando sopra restituirà:
$ 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
Si noti che mi capita di avere un uso .
seguito da uno spazio che non è utilizzato per l'approvvigionamento, ma è perché ho un alias che chiama un'altra lingua, non bash. Questo è ciò che dà lo strano $a*100/$c
e ")\n"'
nell'output sopra. Ma questo può essere ignorato.
Infine, ecco come mettere tutto insieme e cercare un nome di funzione in tutti i file predefiniti e in tutti i file che i tuoi file predefiniti provengono:
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
}
Aggiungi quelle righe al tuo ~/.bashrc
e puoi quindi eseguire (sto usando fooBar
come nome di funzione di esempio):
grep_function fooBar
Ad esempio, se ho questa riga nel mio ~/.bashrc
:
. ~/a
E il file ~/a
è:
$ cat ~/a
fooBar(){
echo foo
}
Dovrei trovarlo con:
$ grep_function fooBar
/home/terdon/a:fooBar(){
+=
array+="foo"
aggiungere la stringa foo
al primo elemento dell'array?
Le solitebash
letture dotfile per utente sono ~/.bashrc
. Tuttavia, può benissimo reperire altri file, ad esempio mi piace mantenere alias e funzioni in file separati chiamati ~/.bash_aliases
e ~/.bash_functions
, il che rende molto più facile trovarli. È possibile cercare il .bashrc
per source
comandi con:
grep -E '(^\s*|\s)(\.|source)\s' /home/USERNAME/.bashrc
Una volta che hai l'elenco dei file creati dall'utente puoi cercarli e l'utente .bashrc
con una sola grep
chiamata, ad es. Per la funzione foo
per la mia configurazione:
grep foo /home/USERNAME/.bash{rc,_aliases,_functions}