Kìa! Chức năng vỏ 12-line ... kỹ thuật bash- và zsh-Portable mạnh mẽ về mặt kỹ thuật , cực kỳ yêu thích kịch bản khởi động ~/.bashrc
hoặc ~/.zshrc
lựa chọn của bạn:
# void +path.append(str dirname, ...)
#
# Append each passed existing directory to the current user's ${PATH} in a
# safe manner silently ignoring:
#
# * Relative directories (i.e., *NOT* prefixed by the directory separator).
# * Duplicate directories (i.e., already listed in the current ${PATH}).
# * Nonextant directories.
+path.append() {
# For each passed dirname...
local dirname
for dirname; do
# Strip the trailing directory separator if any from this dirname,
# reducing this dirname to the canonical form expected by the
# test for uniqueness performed below.
dirname="${dirname%/}"
# If this dirname is either relative, duplicate, or nonextant, then
# silently ignore this dirname and continue to the next. Note that the
# extancy test is the least performant test and hence deferred.
[[ "${dirname:0:1}" == '/' &&
":${PATH}:" != *":${dirname}:"* &&
-d "${dirname}" ]] || continue
# Else, this is an existing absolute unique dirname. In this case,
# append this dirname to the current ${PATH}.
PATH="${PATH}:${dirname}"
done
# Strip an erroneously leading delimiter from the current ${PATH} if any,
# a common edge case when the initial ${PATH} is the empty string.
PATH="${PATH#:}"
# Export the current ${PATH} to subprocesses. Although system-wide scripts
# already export the ${PATH} by default on most systems, "Bother free is
# the way to be."
export PATH
}
Chuẩn bị cho mình vinh quang tức thời. Sau đó, thay vì làm điều này và mong muốn điều tốt nhất:
export PATH=$PATH:~/opt/bin:~/the/black/goat/of/the/woods/with/a/thousand/young
Thay vào đó, hãy làm điều này và được đảm bảo có được thứ tốt nhất, cho dù bạn có thực sự muốn điều đó hay không:
+path.append ~/opt/bin ~/the/black/goat/of/the/woods/with/a/thousand/young
Rất tốt, Xác định "Tốt nhất."
Bổ sung và chuẩn bị một cách an toàn vào hiện tại ${PATH}
không phải là chuyện nhỏ mà nó thường được thực hiện. Mặc dù thuận tiện và có vẻ hợp lý, một trong những mẫu đơn export PATH=$PATH:~/opt/bin
mời các biến chứng ma quỷ với:
Vô tình dirnames tương đối (ví dụ, export PATH=$PATH:opt/bin
). Trong khi bash
và zsh
âm thầm chấp nhận và chủ yếu bỏ qua các dirnam tương đối trong hầu hết các trường hợp, các dirnam tương đối được tiền tố bởi một trong hai ( h
hoặc t
có thể các nhân vật bất chính khác) khiến cả hai phải xấu hổ tự cắt xén kiệt tác bán kết năm 1962 của Masaki Kobayashi Harakiri :
# Don't try this at home. You will feel great pain.
$ PATH='/usr/local/bin:/usr/bin:/bin' && export PATH=$PATH:harakiri && echo $PATH
/usr/local/bin:/usr/bin:arakiri
$ PATH='/usr/local/bin:/usr/bin:/bin' && export PATH=$PATH:tanuki/yokai && echo $PATH
binanuki/yokai # Congratulations. Your system is now face-up in the gutter.
Vô tình trùng lặp dirnames. Mặc dù các ${PATH}
dirnam trùng lặp phần lớn là vô hại, chúng cũng không mong muốn, cồng kềnh, kém hiệu quả, cản trở khả năng sửa lỗi và thúc đẩy hao mòn ổ đĩa - giống như câu trả lời này. Mặc dù SSD kiểu NAND ( tất nhiên ) miễn nhiễm với đọc, nhưng ổ cứng thì không. Truy cập hệ thống tập tin không cần thiết trên mỗi lệnh đã thử ngụ ý hao mòn đầu đọc không cần thiết ở cùng một nhịp độ. Các bản sao đặc biệt không rõ ràng khi gọi các vỏ được lồng trong các quy trình lồng nhau, tại thời điểm đó, các lớp lót dường như vô hại như export PATH=$PATH:~/wat
nhanh chóng nổ tung vào Vòng tròn thứ bảy ${PATH}
như địa ngục PATH=/usr/local/bin:/usr/bin:/bin:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat
. Chỉ Beelzebubba có thể giúp bạn nếu sau đó bạn thêm các tên khác vào đó. (Đừng để điều này xảy ra với những đứa trẻ quý giá của bạn. )
- Vô tình thiếu dirnames. Một lần nữa, trong khi thiếu các
${PATH}
tên miền chủ yếu là vô hại, chúng cũng thường không mong muốn, cồng kềnh, kém hiệu quả, cản trở khả năng sửa lỗi và thúc đẩy hao mòn ổ đĩa.
Ergo, tự động hóa thân thiện như chức năng shell được xác định ở trên. Chúng ta phải tự cứu mình khỏi chính mình.
Nhưng ... Tại sao "+ path.append ()"? Tại sao không chỉ đơn giản là append_path ()?
Đối với tính không rõ ràng (ví dụ: với các lệnh bên ngoài trong các ${PATH}
hàm shell hiện tại hoặc toàn hệ thống được xác định ở nơi khác), các hàm shell do người dùng định nghĩa là tiền tố hoặc hậu tố lý tưởng được hỗ trợ bởi bash
và zsh
nhưng bị cấm đối với các tên cơ sở lệnh tiêu chuẩn - như, giả sử +
.
Chào. Nó hoạt động. Đừng phán xét tôi.
Nhưng ... Tại sao "+ path.append ()"? Tại sao không "+ path.prepend ()"?
Bởi vì nối thêm vào hiện tại ${PATH}
an toàn hơn so với trả trước cho hiện tại ${PATH}
, tất cả mọi thứ đều bình đẳng, điều mà chúng không bao giờ được. Việc ghi đè các lệnh trên toàn hệ thống bằng các lệnh dành riêng cho người dùng có thể không đảm bảo tốt nhất và làm cho điên rồ nhất. Ví dụ, trong Linux, các ứng dụng xuôi dòng thường mong đợi các biến thể lệnh lõi của GNU thay vì các dẫn xuất hoặc các lựa chọn thay thế không chuẩn.
Điều đó nói rằng, hoàn toàn có trường hợp sử dụng hợp lệ để làm như vậy. Xác định +path.prepend()
hàm tương đương là tầm thường. Sans prolix nebulity, cho sự tỉnh táo chia sẻ của anh ấy và cô ấy:
+path.prepend() {
local dirname
for dirname in "${@}"; do
dirname="${dirname%/}"
[[ "${dirname:0:1}" == '/' &&
":${PATH}:" != *":${dirname}:"* &&
-d "${dirname}" ]] || continue
PATH="${dirname}:${PATH}"
done
PATH="${PATH%:}"
export PATH
}
Nhưng ... Tại sao không phải là Gilles?
Câu trả lời được chấp nhận của Gilles ở nơi khác là tối ưu một cách ấn tượng trong trường hợp chung như là một "phần phụ bất khả tri bất khả tri" . Trong trường hợp chung của bash
và zsh
với không Tuy nhiên, liên kết tượng trưng không mong muốn, hình phạt hiệu suất cần phải như vậy rất buồn các ricer Gentoo trong tôi. Ngay cả khi có sự hiện diện của các liên kết tượng trưng không mong muốn, vẫn còn tranh cãi liệu việc bỏ một chuỗi con trên mỗi add_to_PATH()
đối số có đáng để chèn các liên kết trùng lặp tiềm năng hay không.
Đối với các trường hợp sử dụng nghiêm ngặt yêu cầu loại bỏ ngay cả các bản sao liên kết tượng trưng, zsh
biến thể cụ thể này thực hiện điều đó thông qua các nội dung hiệu quả thay vì các nhánh không hiệu quả:
+path.append() {
local dirname
for dirname in "${@}"; do
dirname="${dirname%/}"
[[ "${dirname:0:1}" == '/' &&
":${PATH}:" != *":${dirname:A}:"* &&
-d "${dirname}" ]] || continue
PATH="${PATH}:${dirname}"
done
PATH="${PATH#:}"
export PATH
}
Lưu ý *":${dirname:A}:"*
thay vì *":${dirname}:"*
của bản gốc. :A
là một chủ nghĩa kỳ diệu zsh
đáng buồn vắng mặt dưới hầu hết các vỏ khác - bao gồm cả bash
. Để trích dẫn man zshexpn
:
Trả lời : Biến tên tệp thành một đường dẫn tuyệt đối như công cụ a
sửa đổi thực hiện, sau đó chuyển kết quả qua realpath(3)
chức năng thư viện để giải quyết các liên kết tượng trưng. Lưu ý: trên các hệ thống không có realpath(3)
chức năng thư viện, các liên kết tượng trưng không được giải quyết, do đó, trên các hệ thống đó a
và A
tương đương.
Không có câu hỏi nào nữa.
Không có gì. Thưởng thức pháo kích an toàn. Bây giờ bạn xứng đáng với nó.