tương đương zsh của bash's export -f là gì


24

Vì vậy, tôi bắt đầu sử dụng zsh. Tôi thích nó đúng Nó có vẻ rất hay và lắt léo, và thực tế là thư mục làm việc hiện tại và dòng lệnh thực tế nằm trên các dòng khác nhau là tốt, nhưng đồng thời, tôi nhận thấy rằng zshcó thể chậm hơn một chút bash, đặc biệt là khi in văn bản sang màn.

Điều tôi thích nhất là thực tế zshlà 'tương thích ngược' với tất cả các chức năng tôi đã xác định trong .bashrc.

Mặc dù vậy, một nắm. Tất cả các chức năng đều hoạt động hoàn hảo, nhưng tôi không thể hiểu hệ thống xuất khẩu hoạt động như thế nào.

Tôi đã có một số .bashrcchức năng được xuất để tôi có thể sử dụng chúng ở nơi khác, chẳng hạn như trong tập lệnh và chương trình bên ngoài export -f.

Trong zsh, xuất khẩu dường như thậm chí không được nói đến. Có phải nó tự động tải? Có phải hai điều đó giống nhau không? Tôi đang có một thời gian khó khăn nghiêm trọng để tìm ra điều đó.


2
Đây là một câu hỏi rất cũ, nhưng tôi muốn nói rằng "thư mục làm việc hiện tại và dòng lệnh thực tế nằm trên các dòng khác nhau" không liên quan gì đến zsh. Nó phụ thuộc vào cách bạn thiết lập lời nhắc của mình, thế thôi.
4ae1e1

Câu trả lời:


11

Các biến môi trường chứa các hàm là một bash hack. Zsh không có gì tương tự. Bạn có thể làm một cái gì đó tương tự với một vài dòng mã. Biến môi trường chứa chuỗi; các phiên bản cũ hơn của bash, trước khi Shellshock được phát hiện, đã lưu mã của hàm trong một biến có tên là hàm và có giá trị được () {theo sau bởi mã của hàm }. Bạn có thể sử dụng mã sau đây để nhập các biến với mã hóa này và thử chạy chúng với các cài đặt giống như bash. Lưu ý rằng zsh không thể mô phỏng tất cả các tính năng bash, tất cả những gì bạn có thể làm là tiến gần hơn một chút (ví dụ: để $foophân chia giá trị và mở rộng ký tự đại diện và tạo mảng dựa trên 0).

bash_function_preamble='
    emulate -LR ksh
'
for name in ${(k)parameters}; do
  [[ "-$parameters[name]-" = *-export-* ]] || continue
  [[ ${(P)name} = '() {'*'}' ]] || continue
  ((! $+builtins[$name])) || continue
  functions[$name]=$bash_function_preamble${${${(P)name}#"() {"}%"}"}
done

(Như Stéphane Chazelas , người phát hiện ban đầu của Shellshock, lưu ý, phiên bản trước của câu trả lời này có thể thực thi mã tùy ý vào thời điểm này nếu định nghĩa hàm bị sai. Phiên bản này không, nhưng tất nhiên ngay khi bạn thực hiện bất kỳ lệnh nào, nó có thể là một hàm được nhập từ môi trường.)

Các phiên bản Post-Shellshock của các hàm mã hóa bash trong môi trường sử dụng tên biến không hợp lệ (ví dụ BASH_FUNC_myfunc%%). Điều này làm cho chúng khó phân tích đáng tin cậy hơn vì zsh không cung cấp giao diện để trích xuất các tên biến như vậy từ môi trường.

Tôi không khuyên bạn nên làm điều này. Dựa vào các chức năng được xuất trong các tập lệnh là một ý tưởng tồi: nó tạo ra sự phụ thuộc vô hình trong tập lệnh của bạn. Nếu bạn từng chạy tập lệnh của mình trong một môi trường không có chức năng của bạn (trên một máy khác, trong một công việc định kỳ, sau khi thay đổi các tệp khởi tạo shell của bạn, thì), tập lệnh của bạn sẽ không hoạt động nữa. Thay vào đó, lưu trữ tất cả các chức năng của bạn trong một hoặc nhiều tệp riêng biệt (đại loại như ~/lib/shell/foo.sh) và bắt đầu tập lệnh của bạn bằng cách nhập các hàm mà nó sử dụng ( . ~/lib/shell/foo.sh). Bằng cách này, nếu bạn sửa đổi foo.sh, bạn có thể dễ dàng tìm kiếm tập lệnh nào đang dựa vào nó. Nếu bạn sao chép một tập lệnh, bạn có thể dễ dàng tìm ra tập tin phụ trợ nào.

Zsh (và ksh trước nó) làm cho điều này thuận tiện hơn bằng cách cung cấp cách tự động tải các hàm trong các tập lệnh nơi chúng được sử dụng. Hạn chế là bạn chỉ có thể đặt một chức năng cho mỗi tệp. Khai báo hàm dưới dạng tự động tải và đặt định nghĩa hàm vào một tệp có tên là tên của hàm. Đặt tệp này trong một thư mục được liệt kê trong $fpath(mà bạn có thể định cấu hình thông qua FPATHbiến môi trường). Trong tập lệnh của bạn, khai báo các hàm tự động tải với autoload -U foo.

Hơn nữa, zsh có thể biên dịch các tập lệnh, để tiết kiệm thời gian phân tích cú pháp. Gọi zcompileđể biên dịch một kịch bản. Điều này tạo ra một tập tin với .zwcphần mở rộng. Nếu tệp này có mặt thì autoloadsẽ tải tệp đã biên dịch thay vì mã nguồn. Bạn có thể sử dụng zrecompilehàm để (biên dịch lại) tất cả các định nghĩa hàm trong một thư mục.


1
Thật buồn cười là mã của bạn có cùng lỗ hổng shellshock như thế nào bash(không xác minh rằng nội dung của biến chỉ là một định nghĩa hàm và xử lý bất kỳ tên biến nào như HTTP_HOSThoặc LC_X). Tốt trả lời khác.
Stéphane Chazelas

@ StéphaneChazelas Nếu bạn định chạy các lệnh với các chức năng được nhập từ môi trường, bạn đã mất khá nhiều. Nhưng tôi đã cập nhật mã nhập để không thực thi mã tùy ý. Mặc dù vậy, nó không hữu ích lắm, vì bash post-shellshock không mã hóa các hàm xuất của nó theo cùng một cách.
Gilles 'SO- đừng trở nên xấu xa'

Bây giờ bạn đã sửa lỗi tương đương với CVE-2014-6271, nhưng vẫn có thể gặp phải nhiều lỗ hổng thuộc loại CVE-2014-6277 / 6278 ... vì bạn vẫn đang hiển thị trình phân tích cú pháp zsh thành mã trong bất kỳ biến nào bao gồm một số có khả năng dưới sự kiểm soát của những kẻ tấn công trong một số bối cảnh (vì mã trong zsh -c 'functions[f]=$VAR' được phân tích cú pháp ngay cả khi fhàm không bao giờ được gọi). Giải pháp là chỉ xem xét các biến có tên theo mẫu dành riêng như các biến đó $BASH_FUNC_x%%, nhưng như bạn nói, zshkhông có API để liệt kê hoặc truy xuất các biến đó. Bạn cần gọi perlchẳng hạn.
Stéphane Chazelas

7

Nếu bạn đặt khai báo hàm của bạn trong .zshenv , hàm của bạn sẽ có thể sử dụng được từ một tập lệnh mà không cần bất kỳ nỗ lực nào.


Tại sao bạn downvote câu trả lời của tôi? Vui lòng giải thích.
Rools

Vẫn đang chờ câu trả lời và vẫn làm việc!
Rools

Tôi chỉ phát hiện ra câu trả lời này và nó là một giải pháp lý tưởng.
AFH

Tôi đã không downvote nó. Và TBH OP đã hỏi về việc xuất nội dung từ .bashrc, đây là một ý tưởng tồi, tốt hơn là đưa nó vào một tập lệnh để bạn không phải chịu một môi trường rộng lớn. Nhưng giải pháp của bạn chỉ là một biến thể của cùng một ý tưởng tồi tệ đó, hãy đặt tất cả các tập lệnh của bạn vào .zshenvvà nó làm chậm mọi lời gọi của zsh bằng cách phân tích nhiều mã không bao giờ được sử dụng. Hơn nữa, nó không giống như xuất một hàm, giống như một biến được xuất, một hàm xuất chỉ có sẵn cho các tiến trình con. Trong khi những thứ bạn đưa vào .zshenvcó sẵn cho mọi zsh.
Biến thái

Cuối cùng, nếu bạn dựa vào mã cá nhân mà bạn đặt vào .zshenv, thì tất cả các tập lệnh của bạn sẽ hoàn toàn không thể mang theo được. Thông thường các tập lệnh có thể phụ thuộc lẫn nhau, điều này tốt, bạn phân phối chúng cùng nhau. Nhưng nếu chúng phụ thuộc vào việc có các chức năng đặc biệt .zshenv, sẽ không ai muốn sử dụng chúng, hoặc chúng sẽ phải được gọi với một đặc biệt ZDOTDIR, ngăn không cho chính bạn .zshenvthực thi. Nó sẽ là một nỗi đau.
Biến thái
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.