Bagaimana saya bisa menemukan di mana fungsi bash tertentu didefinisikan?
28
Ada banyak fungsi yang bisa digunakan di Bash shell. Definisi mereka dapat didaftar oleh set, tetapi bagaimana menemukan file mana yang didefinisikan fungsi tertentu oleh pengguna?
Jika diset pada permintaan shell, atau dalam file startup shell, atur untuk menjalankan profil debugger sebelum shell dimulai, identik dengan
--debuggeropsi. Jika disetel setelah pemanggilan, perilaku yang dimaksudkan untuk digunakan oleh para debugger diaktifkan:
The -Fpilihan untuk declarebuiltin (lihat Bash builtin ) menampilkan sumber nama file dan nomor baris yang sesuai untuk setiap nama fungsi yang disediakan sebagai argumen.
Ini adalah solusi yang bagus dan sederhana. Seperti misalnya Anda, itu bahkan tidak diperlukan untuk memulai shell baru: shopt -s extdebug; declare -Ff quote; shopt -u extdebug.
jarno
2
@ Jarno ah, yah, bertentangan dengan nama saya, saya menggunakan zsh. Itu sebabnya saya memulai shell baru. : D
bashity mcbashface
Apakah ada metode serupa untuk menemukan lokasi deklarasi alias ?
FedonKadifeli
@ fedon pendekatan saya yang berbelit-belit dan rumit di bawah ini seharusnya berhasil.
terdon
1
Anda bisa membuat ini fungsi seperti ini: find_function()( shopt -s extdebug; declare -F "$@"; ). Dengan parens pada badan fungsi, dieksekusi dalam subkulit dan perubahan ke shopts tidak memengaruhi pemanggil. Dan -fsepertinya tidak dibutuhkan.
wjandrea
15
Ini sebenarnya lebih rumit daripada yang muncul pada awalnya. File mana yang dibaca oleh shell Anda tergantung pada jenis shell yang sedang Anda jalankan. Apakah itu interaktif atau tidak, apakah itu login atau shell non-login dan apa kombinasi di atas. Untuk mencari semua file default yang dapat dibaca oleh shell yang berbeda, Anda dapat melakukannya (mengubah $functionNameke nama sebenarnya dari fungsi yang Anda cari):
Itu mungkin perlu penjelasan. Yang -Pmemungkinkan Perl Compatible Regular Expressions (PCRE) yang memungkinkan kami menggunakan sintaks regex yang lebih menarik. Secara khusus:
(^|\s): cocok dengan awal suatu baris ( ^) atau spasi putih ( \s).
(\.|source)\s+: cocok dengan .karakter literal ( \.) atau kata source, tetapi hanya jika mereka diikuti oleh satu atau lebih karakter spasi putih.
Seperti yang Anda lihat, bagaimanapun, ini akan mencetak seluruh baris yang cocok. Yang benar-benar kami minati adalah daftar nama file yang dipanggil, bukan baris yang memanggil mereka. Anda bisa mendapatkannya dengan ini, lebih rumit, regex:
The -hbendera menekan pencetakan nama file di mana pertandingan ditemukan, yang greptidak secara default ketika diberitahu untuk mencari melalui beberapa file. The -oberarti "hanya mencetak bagian pencocokan dari garis". Hal-hal tambahan yang ditambahkan ke regex adalah:
\K: abaikan apa pun yang cocok dengan titik ini. Ini adalah trik PCRE yang memungkinkan Anda menggunakan regex kompleks untuk menemukan pasangan Anda, tetapi tidak menyertakan bagian yang cocok saat menggunakan -obendera grep .
Perhatikan bahwa saya kebetulan menggunakan .diikuti oleh ruang yang tidak digunakan untuk sumber tetapi itu karena saya memiliki alias yang memanggil bahasa lain, bukan bash. Itulah yang memberi keanehan $a*100/$cdan ")\n"'pada output di atas. Tapi itu bisa diabaikan.
Terakhir, inilah cara menyatukan semua itu dan mencari nama fungsi di semua file default dan semua file yang menjadi sumber file default Anda:
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"fidone}
Tambahkan baris-baris itu ke Anda ~/.bashrcdan Anda kemudian dapat menjalankan (saya menggunakan fooBarsebagai contoh nama fungsi):
grep_function fooBar
Misalnya, jika saya memiliki baris ini di ~/.bashrc:
Solusi Anda adalah contoh skrip pendidikan yang hebat, tetapi saya menemukan solusi bashity mcbashface lebih sederhana.
jarno
@ Jarno dan itu jauh, lebih sederhana! :)
terdon
Dukungan array+=
D. Ben Knoble
@ D.BenKnoble yang mereka lakukan? Maksud Anda selain array+="foo"menambahkan string fooke elemen pertama array?
terdon
1
@ D.BenKnoble terima kasih! Saya tidak tahu bash arrays mendukung notasi itu!
terdon
2
The biasa per-user dotfile bashmembaca adalah ~/.bashrc. Namun, mungkin sumber file lain sangat baik, saya misalnya ingin menjaga alias dan fungsi dalam file terpisah yang disebut ~/.bash_aliasesdan ~/.bash_functions, yang membuatnya lebih mudah menemukannya. Anda dapat mencari .bashrcuntuk sourceperintah dengan:
Setelah Anda memiliki daftar file yang dibuat pengguna, Anda dapat mencarinya dan pengguna .bashrcdengan satu greppanggilan, misalnya untuk fungsi foopengaturan saya:
Jawaban:
Aktifkan debugging. Dari manual Bash :
Contoh:
Dan memang:
sumber
shopt -s extdebug; declare -Ff quote; shopt -u extdebug
.find_function()( shopt -s extdebug; declare -F "$@"; )
. Dengan parens pada badan fungsi, dieksekusi dalam subkulit dan perubahan ke shopts tidak memengaruhi pemanggil. Dan-f
sepertinya tidak dibutuhkan.Ini sebenarnya lebih rumit daripada yang muncul pada awalnya. File mana yang dibaca oleh shell Anda tergantung pada jenis shell yang sedang Anda jalankan. Apakah itu interaktif atau tidak, apakah itu login atau shell non-login dan apa kombinasi di atas. Untuk mencari semua file default yang dapat dibaca oleh shell yang berbeda, Anda dapat melakukannya (mengubah
$functionName
ke nama sebenarnya dari fungsi yang Anda cari):Jika itu tidak berhasil, Anda mungkin memanggil file non-default menggunakan
.
atau aliasnyasource
. Untuk menemukan kasus seperti itu, jalankan:Itu mungkin perlu penjelasan. Yang
-P
memungkinkan Perl Compatible Regular Expressions (PCRE) yang memungkinkan kami menggunakan sintaks regex yang lebih menarik. Secara khusus:(^|\s)
: cocok dengan awal suatu baris (^
) atau spasi putih (\s
).(\.|source)\s+
: cocok dengan.
karakter literal (\.
) atau katasource
, tetapi hanya jika mereka diikuti oleh satu atau lebih karakter spasi putih.Inilah yang memberi saya pada sistem saya:
Seperti yang Anda lihat, bagaimanapun, ini akan mencetak seluruh baris yang cocok. Yang benar-benar kami minati adalah daftar nama file yang dipanggil, bukan baris yang memanggil mereka. Anda bisa mendapatkannya dengan ini, lebih rumit, regex:
The
-h
bendera menekan pencetakan nama file di mana pertandingan ditemukan, yanggrep
tidak secara default ketika diberitahu untuk mencari melalui beberapa file. The-o
berarti "hanya mencetak bagian pencocokan dari garis". Hal-hal tambahan yang ditambahkan ke regex adalah:\K
: abaikan apa pun yang cocok dengan titik ini. Ini adalah trik PCRE yang memungkinkan Anda menggunakan regex kompleks untuk menemukan pasangan Anda, tetapi tidak menyertakan bagian yang cocok saat menggunakan-o
bendera grep .Di sistem saya, perintah di atas akan kembali:
Perhatikan bahwa saya kebetulan menggunakan
.
diikuti oleh ruang yang tidak digunakan untuk sumber tetapi itu karena saya memiliki alias yang memanggil bahasa lain, bukan bash. Itulah yang memberi keanehan$a*100/$c
dan")\n"'
pada output di atas. Tapi itu bisa diabaikan.Terakhir, inilah cara menyatukan semua itu dan mencari nama fungsi di semua file default dan semua file yang menjadi sumber file default Anda:
Tambahkan baris-baris itu ke Anda
~/.bashrc
dan Anda kemudian dapat menjalankan (saya menggunakanfooBar
sebagai contoh nama fungsi):Misalnya, jika saya memiliki baris ini di
~/.bashrc
:Dan file tersebut
~/a
adalah:Saya harus menemukannya dengan:
sumber
+=
array+="foo"
menambahkan stringfoo
ke elemen pertama array?The biasa per-user dotfile
bash
membaca adalah~/.bashrc
. Namun, mungkin sumber file lain sangat baik, saya misalnya ingin menjaga alias dan fungsi dalam file terpisah yang disebut~/.bash_aliases
dan~/.bash_functions
, yang membuatnya lebih mudah menemukannya. Anda dapat mencari.bashrc
untuksource
perintah dengan:Setelah Anda memiliki daftar file yang dibuat pengguna, Anda dapat mencarinya dan pengguna
.bashrc
dengan satugrep
panggilan, misalnya untuk fungsifoo
pengaturan saya:sumber