Câu trả lời:
Bật gỡ lỗi. Từ hướng dẫn Bash :
extdebug
Nếu được đặt ở lệnh gọi shell hoặc trong tệp khởi động shell, hãy sắp xếp để thực thi cấu hình trình gỡ lỗi trước khi shell bắt đầu, giống hệt với
--debugger
tùy chọn. Nếu được đặt sau khi gọi, hành vi được sử dụng bởi trình gỡ lỗi được bật:
- Các
-F
tùy chọn vàodeclare
BUILTIN (xem Bash builtins ) hiển thị tên file nguồn và dòng số tương ứng với mỗi tên hàm được cung cấp như một cuộc tranh cãi.
Thí dụ:
$ bash --debugger
$ declare -Ff quote
quote 143 /usr/share/bash-completion/bash_completion
Và thực sự:
$ 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 "$@"; )
. Với các parens trên thân hàm, nó được thực thi trong một lớp con và thay đổi đối với các cửa hàng không ảnh hưởng đến người gọi. Và -f
dường như không cần thiết.
Điều này thực sự phức tạp hơn lúc đầu. Những tập tin nào được đọc bởi shell của bạn phụ thuộc vào loại shell nào bạn đang chạy. Cho dù đó là tương tác hay không, cho dù đó là một đăng nhập hoặc một vỏ không đăng nhập và sự kết hợp của những điều trên. Để tìm kiếm trong tất cả các tệp mặc định có thể được đọc bởi các shell khác nhau, bạn có thể thực hiện (thay đổi $functionName
tên thực của chức năng bạn đang tìm kiếm):
grep "$functionName" ~/.bashrc ~/.profile ~/.bash_profile ~/.bash.login \
~/.bash_aliases /etc/bash.bashrc /etc/profile \
/etc/profile.d/* /etc/environment 2> /dev/null
Nếu điều đó không làm việc, bạn có thể gọi một tệp không mặc định bằng cách sử dụng .
hoặc bí danh của nó source
. Để tìm trường hợp như vậy, chạy:
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
Điều đó có lẽ cần một số lời giải thích. Cho -P
phép biểu thức tương thích thường xuyên tương thích Perl (PCRE) cho phép chúng tôi sử dụng một số cú pháp regex fancier. Đặc biệt:
(^|\s)
: khớp với phần đầu của một dòng ( ^
) hoặc khoảng trắng ( \s
).(\.|source)\s+
: khớp với một ký .
tự bằng chữ ( \.
) hoặc từ source
, nhưng chỉ khi chúng được theo sau bởi một hoặc nhiều ký tự khoảng trắng.Đây là những gì mang lại cho tôi trên hệ thống của tôi:
$ 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
Như bạn có thể thấy, tuy nhiên, điều này sẽ in toàn bộ dòng phù hợp. Điều chúng tôi thực sự quan tâm là danh sách các tên tệp được gọi, không phải là dòng đang gọi chúng. Bạn có thể nhận được những thứ có điều này, phức tạp hơn, 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
Các -h
cờ ngăn chặn việc in ấn của tên tập tin mà một trận đấu đã được tìm thấy, trong đó grep
thực hiện theo mặc định khi nói đến tìm kiếm thông qua nhiều file. Có -o
nghĩa là "chỉ in phần phù hợp của dòng". Các công cụ bổ sung được thêm vào regex là:
\K
: bỏ qua bất cứ điều gì phù hợp cho đến thời điểm này. Đây là một thủ thuật PCRE cho phép bạn sử dụng một biểu thức chính quy phức tạp để tìm trận đấu của mình nhưng không bao gồm phần phù hợp đó khi sử dụng -o
cờ của grep .Trên hệ thống của tôi, lệnh trên sẽ trả về:
$ 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
Lưu ý rằng tôi tình cờ sử dụng .
một không gian không được sử dụng để tìm nguồn cung ứng nhưng đó là vì tôi có một bí danh đang gọi một ngôn ngữ khác, không phải là bash. Đó là những gì mang lại sự kỳ lạ $a*100/$c
và ")\n"'
ở đầu ra ở trên. Nhưng điều đó có thể bị bỏ qua.
Cuối cùng, đây là cách kết hợp tất cả những thứ đó lại với nhau và tìm kiếm một tên hàm trong tất cả các tệp mặc định và tất cả các tệp mà các tệp mặc định của bạn đang tìm nguồn:
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
}
Thêm các dòng đó vào của bạn ~/.bashrc
và sau đó bạn có thể chạy (Tôi đang sử dụng fooBar
làm tên hàm ví dụ):
grep_function fooBar
Ví dụ: nếu tôi có dòng này trong ~/.bashrc
:
. ~/a
Và tập tin ~/a
là:
$ cat ~/a
fooBar(){
echo foo
}
Tôi nên tìm nó với:
$ grep_function fooBar
/home/terdon/a:fooBar(){
+=
array+="foo"
việc nối thêm chuỗi foo
vào phần tử thứ 1 của mảng?
Các thông thường cho mỗi người dùng dotfile bash
đọc là ~/.bashrc
. Tuy nhiên, nó có thể cung cấp nguồn rất tốt cho các tệp khác, ví dụ như tôi muốn giữ bí danh và hàm trong các tệp riêng biệt được gọi ~/.bash_aliases
và ~/.bash_functions
điều này giúp việc tìm kiếm chúng dễ dàng hơn nhiều. Bạn có thể tìm kiếm .bashrc
cho source
lệnh với:
grep -E '(^\s*|\s)(\.|source)\s' /home/USERNAME/.bashrc
Khi bạn có danh sách các tệp do người dùng tạo, bạn có thể tìm kiếm chúng và người dùng chỉ .bashrc
bằng một grep
cuộc gọi, ví dụ như chức năng foo
cho thiết lập của tôi:
grep foo /home/USERNAME/.bash{rc,_aliases,_functions}