Saya kesulitan mendefinisikan dan menjalankan fungsi shell saya sendiri di zsh. Saya mengikuti instruksi pada dokumentasi resmi dan mencoba dengan contoh mudah terlebih dahulu, tetapi saya gagal membuatnya bekerja.
Saya punya folder:
~/.my_zsh_functions
Dalam folder ini saya memiliki file yang dipanggil functions_1
dengan rwx
izin pengguna. Dalam file ini saya mendefinisikan fungsi shell berikut:
my_function () {
echo "Hello world";
}
Saya menetapkan FPATH
untuk memasukkan path ke folder ~/.my_zsh_functions
:
export FPATH=~/.my_zsh_functions:$FPATH
Saya dapat mengkonfirmasi bahwa folder .my_zsh_functions
tersebut ada di jalur fungsi dengan echo $FPATH
atauecho $fpath
Namun, jika saya mencoba hal berikut dari shell:
> autoload my_function
> my_function
Saya mendapat:
zsh: my_test_function: file definisi fungsi tidak ditemukan
Apakah ada hal lain yang perlu saya lakukan untuk dapat menelepon my_function
?
Memperbarui:
Jawaban sejauh ini menyarankan sumber file dengan fungsi zsh. Ini masuk akal, tetapi saya agak bingung. Bukankah seharusnya zsh tahu di mana file-file itu berada FPATH
? Apa tujuan dari autoload
itu?
sumber
Jawaban:
Di zsh, path pencarian fungsi ($ fpath) mendefinisikan satu set direktori, yang berisi file yang dapat ditandai untuk dimuat secara otomatis ketika fungsi yang dikandungnya diperlukan untuk pertama kalinya.
Zsh memiliki dua mode file autoloading: Cara asli Zsh dan mode lain yang menyerupai autoloading ksh. Yang terakhir aktif jika opsi KSH_AUTOLOAD diatur. Mode asli Zsh adalah default dan saya tidak akan membahas cara lain di sini (lihat "man zshmisc" dan "man zshoptions" untuk detail tentang autoloading gaya ksh).
Baik. Katakanlah Anda mendapat direktori `~ / .zfunc 'dan Anda ingin itu menjadi bagian dari jalur pencarian fungsi, Anda melakukan ini:
Itu menambahkan direktori pribadi Anda ke bagian depan jalur pencarian. Itu penting jika Anda ingin menimpa fungsi dari instalasi zsh dengan milik Anda sendiri (seperti, ketika Anda ingin menggunakan fungsi penyelesaian yang diperbarui seperti `_git 'dari repositori zsh's CVS dengan versi shell yang diinstal lebih lama).
Perlu juga dicatat, bahwa direktori dari `$ fpath 'tidak dicari secara rekursif. Jika Anda ingin direktori pribadi Anda dicari secara rekursif, Anda harus mengurusnya sendiri, seperti ini (cuplikan berikut membutuhkan opsi `EXTENDED_GLOB 'untuk diatur):
Ini mungkin terlihat samar untuk mata yang tidak terlatih, tetapi itu benar-benar hanya menambahkan semua direktori di bawah `~ / .zfunc 'ke` $ fpath', sementara mengabaikan direktori yang disebut "CVS" (yang berguna, jika Anda berencana untuk checkout keseluruhan pohon fungsi dari CVS zsh ke jalur pencarian pribadi Anda).
Mari kita asumsikan Anda punya file `~ / .zfunc / hello 'yang berisi baris berikut:
Yang perlu Anda lakukan sekarang adalah menandai fungsi yang akan dimuat secara otomatis pada referensi pertamanya:
"Apa -Uz tentang?", Anda bertanya? Yah, itu hanya satu set opsi yang akan menyebabkan `autoload 'untuk melakukan hal yang benar, tidak peduli opsi apa yang sedang diatur sebaliknya. `U 'menonaktifkan ekspansi alias saat fungsi sedang dimuat dan` z' memaksa gaya-zsh autoloading bahkan jika `KSH_AUTOLOAD 'diatur untuk alasan apa pun.
Setelah itu diatasi, Anda dapat menggunakan fungsi `halo 'baru Anda:
Sepatah kata tentang sumber file-file ini: Itu hanya salah . Jika Anda akan sumber file `~ / .zfunc / hello ', itu hanya akan mencetak" Hello world. " sekali. Tidak ada lagi. Tidak ada fungsi yang akan ditentukan. Dan selain itu, idenya adalah untuk hanya memuat kode fungsi saat diperlukan . Setelah panggilan `pengisian otomatis ', definisi fungsi tidak dibaca. Fungsi baru saja ditandai untuk diisikan otomatis nanti sesuai kebutuhan.
Dan akhirnya, catatan tentang $ FPATH dan $ fpath: Zsh mempertahankan itu sebagai parameter yang ditautkan. Parameter huruf kecil adalah sebuah array. Versi huruf besar adalah skalar string, yang berisi entri dari array tertaut yang bergabung dengan titik dua di antara entri. Ini dilakukan, karena menangani daftar skalar adalah cara yang lebih alami menggunakan array, sementara juga menjaga kompatibilitas mundur untuk kode yang menggunakan parameter skalar. Jika Anda memilih untuk menggunakan $ FPATH (skalar), Anda harus berhati-hati:
akan berfungsi, sementara yang berikut tidak akan:
Alasannya adalah bahwa ekspansi tilde tidak dilakukan dalam tanda kutip ganda. Ini kemungkinan sumber masalah Anda. Jika
echo $FPATH
mencetak tilde dan bukan jalur yang diperluas maka itu tidak akan berfungsi. Agar aman, saya akan menggunakan $ HOME alih-alih tilde seperti ini:Yang sedang berkata, saya lebih suka menggunakan parameter array seperti yang saya lakukan di bagian atas penjelasan ini.
Anda juga tidak boleh mengekspor parameter $ FPATH. Ini hanya dibutuhkan oleh proses shell saat ini dan bukan oleh anak-anaknya.
Memperbarui
Mengenai isi file dalam `$ fpath ':
Dengan gaya-otomatis zsh, konten file adalah isi dari fungsi yang ditentukannya. Dengan demikian file bernama "halo" yang mengandung garis
echo "Hello world."
sepenuhnya mendefinisikan fungsi yang disebut "halo". Anda bebas untuk memasukkanhello () { ... }
kode, tetapi itu akan berlebihan.Klaim bahwa satu file hanya boleh berisi satu fungsi tidak sepenuhnya benar.
Terutama jika Anda melihat beberapa fungsi dari fungsi sistem penyelesaian berbasis (compsys) Anda akan segera menyadari bahwa itu adalah kesalahpahaman. Anda bebas menentukan fungsi tambahan dalam file fungsi. Anda juga bebas melakukan inisialisasi apa pun, yang mungkin perlu Anda lakukan saat fungsi pertama kali dipanggil. Namun, ketika Anda melakukannya, Anda akan selalu mendefinisikan fungsi yang dinamai seperti file dalam file dan memanggil fungsi itu di akhir file, sehingga dijalankan saat pertama kali fungsi direferensikan.
Jika - dengan sub-fungsi - Anda tidak mendefinisikan fungsi yang dinamai seperti file di dalam file, Anda akan berakhir dengan fungsi yang memiliki definisi fungsi di dalamnya (yaitu sub-fungsi dalam file). Anda secara efektif akan mendefinisikan semua sub-fungsi Anda setiap kali Anda memanggil fungsi yang dinamai seperti file. Biasanya, itu bukan yang Anda inginkan, jadi Anda akan mendefinisikan ulang suatu fungsi, yang dinamai seperti file di dalam file.
Saya akan menyertakan kerangka pendek, yang akan memberi Anda gambaran tentang cara kerjanya:
Jika Anda menjalankan contoh konyol ini, proses pertama akan terlihat seperti ini:
Dan panggilan berurutan akan terlihat seperti ini:
Saya harap ini jelas.
(Salah satu contoh dunia nyata yang lebih kompleks yang menggunakan semua trik itu adalah fungsi ` _tmux 'yang telah disebutkan dari sistem penyelesaian berbasis fungsi zsh.)
sumber
my_function () { }
dalamHello world
contoh Anda . Jika sintaksis tidak diperlukan, kapan akan berguna untuk menggunakannya?Nama file dalam direktori yang dinamai oleh suatu
fpath
elemen harus cocok dengan nama fungsi yang dapat di-autoload yang didefinisikannya.Fungsi Anda dinamai
my_function
dan~/.my_zsh_functions
merupakan direktori yang dimaksud di Andafpath
, sehingga definisimy_function
harus ada dalam file~/.my_zsh_functions/my_function
.Bentuk jamak dalam nama file yang Anda usulkan (
functions_1
) menunjukkan bahwa Anda berencana untuk meletakkan beberapa fungsi dalam file. Ini bukan bagaimanafpath
dan autoloading bekerja. Anda harus memiliki satu definisi fungsi per file.sumber
berikan
source ~/.my_zsh_functions/functions1
di terminal dan evaluasimy_function
, sekarang Anda akan dapat memanggil fungsisumber
FPATH
danautoload
kemudian? Mengapa saya juga perlu sumber file? Lihat pertanyaan saya yang diperbarui.Anda dapat "memuat" file dengan semua fungsi Anda di $ ZDOTDIR / .zshrc Anda seperti ini:
Atau bisa menggunakan titik "." bukannya "sumber".
sumber
FPATH
danautoload
kemudian? Mengapa saya juga perlu sumber file? Lihat pertanyaan saya yang diperbarui.Sourcing jelas bukan pendekatan yang tepat, karena yang tampaknya Anda inginkan adalah memiliki fungsi inisialisasi malas. Itu untuk apa
autoload
. Inilah cara Anda mencapai apa yang Anda cari.Di Anda
~/.my_zsh_functions
, Anda mengatakan Anda ingin meletakkan fungsi yang disebutmy_function
gema "halo dunia". Tapi, Anda membungkusnya dalam panggilan fungsi, yang bukan cara kerjanya. Sebagai gantinya, Anda perlu membuat file bernama~/.my_zsh_functions/my_function
. Di dalamnya, cukup masukkanecho "Hello world"
, bukan dalam fungsi wrapper. Anda juga dapat melakukan sesuatu seperti ini jika Anda benar-benar memilih untuk memiliki bungkusnya.Selanjutnya, di
.zshrc
file Anda , tambahkan berikut ini:Saat Anda memuat shell ZSH baru, ketik
which my_function
. Anda harus melihat ini:ZSH baru saja mematikan fungsi my_fungsi untuk Anda
autoload -X
. Sekarang, jalankanmy_function
tetapi ketikkan sajamy_function
. Anda akan melihat hasilHello world
cetak, dan sekarang saat Anda menjalankannyawhich my_function
Anda akan melihat fungsi yang diisi seperti ini:Sekarang, keajaiban yang sebenarnya datang ketika Anda mengatur seluruh
~/.my_zsh_functions
folder Anda untuk bekerja dengannyaautoload
. Jika Anda ingin setiap file yang Anda jatuhkan di folder ini berfungsi seperti ini, ubah apa yang Anda masukkan.zshrc
ke dalam sesuatu ini:sumber