Trong zsh, đường dẫn tìm kiếm hàm ($ fpath) xác định một tập hợp các thư mục chứa các tệp có thể được đánh dấu để được tải tự động khi lần đầu tiên chúng chứa hàm cần thiết.
Zsh có hai chế độ tải tập tin tự động: cách riêng của Zsh và chế độ khác tương tự như tự động tải của ksh. Cái sau được kích hoạt nếu tùy chọn KSH_AUTOLOAD được đặt. Chế độ riêng của Zsh là mặc định và tôi sẽ không thảo luận theo cách khác ở đây (xem "man zshmisc" và "man zshoptions" để biết chi tiết về tự động tải kiểu ksh).
Được chứ. Giả sử bạn có một thư mục `~ / .zfunc 'và bạn muốn nó là một phần của đường dẫn tìm kiếm hàm, bạn làm điều này:
fpath=( ~/.zfunc "${fpath[@]}" )
Điều đó thêm thư mục riêng của bạn vào phía trước của đường dẫn tìm kiếm. Điều đó rất quan trọng nếu bạn muốn ghi đè các chức năng từ cài đặt của zsh bằng chính bạn (như, khi bạn muốn sử dụng chức năng hoàn thành được cập nhật, chẳng hạn như `_git 'từ kho lưu trữ CVS của zsh với phiên bản vỏ được cài đặt cũ hơn).
Điều đáng chú ý là các thư mục từ '$ fpath' không được tìm kiếm đệ quy. Nếu bạn muốn thư mục riêng của mình được tìm kiếm đệ quy, bạn sẽ phải tự chăm sóc nó, như thế này (đoạn mã sau yêu cầu tùy chọn `EXTENDED_GLOB '):
fpath=(
~/.zfuncs
~/.zfuncs/**/*~*/(CVS)#(/N)
"${fpath[@]}"
)
Nó có thể trông khó hiểu đối với mắt chưa được huấn luyện, nhưng nó thực sự chỉ thêm tất cả các thư mục bên dưới `~ / .zfunc 'vào` $ fpath', trong khi bỏ qua các thư mục có tên" CVS "(rất hữu ích, nếu bạn dự định kiểm tra toàn bộ cây chức năng từ CVS của zsh vào đường dẫn tìm kiếm riêng tư của bạn).
Giả sử bạn có một tệp `~ / .zfunc / hello 'có chứa dòng sau:
printf 'Hello world.\n'
Tất cả những gì bạn cần làm bây giờ là đánh dấu chức năng sẽ được tự động tải theo tham chiếu đầu tiên của nó:
autoload -Uz hello
"-Uz là về cái gì?", Bạn hỏi? Chà, đó chỉ là một tập hợp các tùy chọn sẽ khiến 'tự động tải' thực hiện đúng, bất kể tùy chọn nào đang được đặt khác. `U 'vô hiệu hóa việc mở rộng bí danh trong khi chức năng đang được tải và` z' buộc tự động tải kiểu zsh ngay cả khi` KSH_AUTOLOAD 'được đặt vì bất kỳ lý do gì.
Sau đó, bạn có thể sử dụng chức năng 'xin chào' mới của mình:
xin chào
Chào thế giới.
Một từ về tìm nguồn cung ứng các tệp này: Điều đó là sai . Nếu bạn nguồn tệp `~ / .zfunc / hello ', nó sẽ chỉ in" Xin chào thế giới. " Một lần. Chỉ có bấy nhiêu thôi. Không có chức năng sẽ được xác định. Và bên cạnh đó, ý tưởng là chỉ tải mã của hàm khi được yêu cầu . Sau khi gọi 'autoload', định nghĩa của hàm không được đọc. Các chức năng chỉ được đánh dấu để tự động tải sau này khi cần thiết.
Và cuối cùng, một lưu ý về $ FPATH và $ fpath: Zsh duy trì chúng là các tham số được liên kết. Tham số chữ thường là một mảng. Phiên bản chữ hoa là một vô hướng chuỗi, chứa các mục từ mảng được liên kết được nối bởi dấu hai chấm ở giữa các mục. Điều này được thực hiện, bởi vì việc xử lý một danh sách các vô hướng là cách tự nhiên hơn khi sử dụng các mảng, trong khi vẫn duy trì khả năng tương thích ngược cho mã sử dụng tham số vô hướng. Nếu bạn chọn sử dụng $ FPATH (số vô hướng), bạn cần cẩn thận:
FPATH=~/.zfunc:$FPATH
sẽ hoạt động, trong khi sau đây sẽ không:
FPATH="~/.zfunc:$FPATH"
Lý do là việc mở rộng dấu ngã không được thực hiện trong dấu ngoặc kép. Đây có thể là nguồn gốc của vấn đề của bạn. Nếu echo $FPATH
in một dấu ngã và không phải là một đường dẫn mở rộng thì nó sẽ không hoạt động. Để an toàn, tôi sẽ sử dụng $ HOME thay vì dấu ngã như thế này:
FPATH="$HOME/.zfunc:$FPATH"
Điều đó đang được nói, tôi muốn sử dụng tham số mảng giống như tôi đã làm ở đầu giải thích này.
Bạn cũng không nên xuất tham số $ FPATH. Nó chỉ cần thiết cho quá trình vỏ hiện tại chứ không phải bởi bất kỳ đứa con nào của nó.
Cập nhật
Về nội dung của các tệp trong `$ fpath ':
Với tính năng tự động tải kiểu zsh, nội dung của tệp là phần thân của hàm được xác định. Do đó, một tệp có tên "hello" chứa một dòng echo "Hello world."
hoàn toàn xác định một chức năng gọi là "xin chào". Bạn có thể tự do đặt
hello () { ... }
mã, nhưng điều đó sẽ không cần thiết.
Tuy nhiên, tuyên bố rằng một tệp chỉ có thể chứa một chức năng không hoàn toàn chính xác.
Đặc biệt nếu bạn xem xét một số chức năng từ hệ thống hoàn thành dựa trên chức năng (compsys), bạn sẽ nhanh chóng nhận ra đó là một quan niệm sai lầm. Bạn có thể tự do xác định các chức năng bổ sung trong một tệp chức năng. Bạn cũng có thể tự do thực hiện bất kỳ loại khởi tạo nào, mà bạn có thể cần thực hiện lần đầu tiên khi hàm được gọi. Tuy nhiên, khi bạn làm, bạn sẽ luôn xác định một hàm có tên giống như tệp trong tệp và gọi hàm đó ở cuối tệp, vì vậy nó sẽ được chạy lần đầu tiên khi hàm được tham chiếu.
Nếu - với các hàm phụ - bạn không xác định hàm có tên như tệp trong tệp, bạn sẽ kết thúc với hàm đó có định nghĩa hàm trong đó (cụ thể là các hàm phụ trong tệp). Bạn thực sự sẽ xác định tất cả các chức năng phụ của mình mỗi khi bạn gọi hàm được đặt tên giống như tệp. Thông thường, đó không phải là điều bạn muốn, vì vậy bạn sẽ xác định lại một hàm, được đặt tên giống như tệp trong tệp.
Tôi sẽ bao gồm một bộ xương ngắn, nó sẽ cho bạn ý tưởng về cách thức hoạt động của nó:
# Let's again assume that these are the contents of a file called "hello".
# You may run arbitrary code in here, that will run the first time the
# function is referenced. Commonly, that is initialisation code. For example
# the `_tmux' completion function does exactly that.
echo initialising...
# You may also define additional functions in here. Note, that these
# functions are visible in global scope, so it is paramount to take
# care when you're naming these so you do not shadow existing commands or
# redefine existing functions.
hello_helper_one () {
printf 'Hello'
}
hello_helper_two () {
printf 'world.'
}
# Now you should redefine the "hello" function (which currently contains
# all the code from the file) to something that covers its actual
# functionality. After that, the two helper functions along with the core
# function will be defined and visible in global scope.
hello () {
printf '%s %s\n' "$(hello_helper_one)" "$(hello_helper_two)"
}
# Finally run the redefined function with the same arguments as the current
# run. If this is left out, the functionality implemented by the newly
# defined "hello" function is not executed upon its first call. So:
hello "$@"
Nếu bạn chạy ví dụ ngớ ngẩn này, lần chạy đầu tiên sẽ như thế này:
xin chào
khởi tạo ...
Chào thế giới.
Và các cuộc gọi liên tiếp sẽ như thế này:
xin chào
Chào thế giới.
Tôi hy vọng điều này sẽ làm mọi thứ rõ ràng.
(Một trong những ví dụ thực tế phức tạp hơn sử dụng tất cả các thủ thuật đó là hàm ` _tmux ' đã được đề cập từ hệ thống hoàn thành dựa trên chức năng của zsh.)