Melihat! 12-line kekuatan-industri ... fungsi bash- dan zsh-portable shell yang secara khusus mencintai skrip startup ~/.bashrc
atau ~/.zshrc
pilihan Anda:
# 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
}
Persiapkan dirimu untuk kemuliaan sesaat. Kemudian, daripada melakukan ini dan berharap yang terbaik:
export PATH=$PATH:~/opt/bin:~/the/black/goat/of/the/woods/with/a/thousand/young
Lakukan ini sebagai gantinya dan dijamin mendapatkan yang terbaik, baik Anda benar-benar menginginkannya atau tidak:
+path.append ~/opt/bin ~/the/black/goat/of/the/woods/with/a/thousand/young
Baiklah, Tentukan "Terbaik."
Aman menambahkan dan menambahkan ke arus ${PATH}
bukanlah masalah sepele seperti yang biasa terjadi. Sementara nyaman dan tampaknya masuk akal, one-liners formulir export PATH=$PATH:~/opt/bin
mengundang komplikasi jahat dengan:
Dirnames relatif tidak sengaja (misalnya, export PATH=$PATH:opt/bin
). Sementara bash
dan zsh
diam - diam menerima dan kebanyakan mengabaikan nama relatif dalam kebanyakan kasus, nama relatif relatif diawali oleh salah satu h
atau t
(dan mungkin karakter jahat lainnya) menyebabkan keduanya memutihkan diri mereka sendiri secara memalukan diri sendiri karya mahakaryanya pada tahun 1962 karya Masaki Kobayashi karya 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.
Duplikasi nama direktori secara tidak sengaja. Meskipun nama ganda duplikat ${PATH}
sebagian besar tidak berbahaya, mereka juga tidak diinginkan, rumit, sedikit tidak efisien, menghambat debuggability, dan mempromosikan drive wear - agak seperti jawaban ini. Sementara SSD gaya NAND ( tentu saja ) kebal terhadap keausan baca, HDD tidak. Akses sistem file yang tidak perlu pada setiap perintah yang dicoba menyiratkan keausan baca yang tidak perlu pada tempo yang sama. Duplikat khususnya tidak berbahaya ketika menggunakan cangkang bersarang di subproses bersarang, di mana titik yang tampaknya tidak berbahaya satu-garis seperti export PATH=$PATH:~/wat
dengan cepat meledak ke dalam Lingkaran ${PATH}
Neraka Ke Tujuh seperti PATH=/usr/local/bin:/usr/bin:/bin:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat
. Hanya Beelzebubba yang dapat membantu Anda jika Anda kemudian menambahkan nama pengguna tambahan ke dalamnya. (Jangan biarkan ini terjadi pada anak-anakmu yang berharga. )
- Dirnames yang hilang secara tidak sengaja. Sekali lagi, meskipun nama yang hilang
${PATH}
sebagian besar tidak berbahaya, mereka juga biasanya tidak diinginkan, rumit, sedikit tidak efisien, menghambat debuggability, dan mempromosikan drive wear.
Ergo, otomatisasi ramah seperti fungsi shell yang didefinisikan di atas. Kita harus menyelamatkan diri kita sendiri.
Tapi ... Kenapa "+ path.append ()"? Kenapa Tidak Cukup append_path ()?
Untuk disambiguitas (misalnya, dengan perintah eksternal dalam ${PATH}
fungsi shell saat ini atau di seluruh sistem yang didefinisikan di tempat lain), fungsi shell yang ditentukan pengguna idealnya diawali atau diakhiri dengan substring unik yang didukung oleh bash
dan zsh
tetapi sebaliknya dilarang untuk nama-nama perintah standar - seperti, misalnya +
,.
Hei. Berhasil. Jangan menilai saya.
Tapi ... Kenapa "+ path.append ()"? Mengapa Tidak "+ path.prepend ()"?
Karena menambahkan ke arus ${PATH}
lebih aman daripada bergantung pada arus ${PATH}
, semua hal dianggap sama, yang tidak pernah ada. Mengganti perintah di seluruh sistem dengan perintah khusus pengguna dapat menjadi tidak bersih paling baik dan paling tidak membuat gila. Di Linux, misalnya, aplikasi hilir umumnya mengharapkan varian perintah GNU coreutils daripada turunan atau alternatif non-standar khusus.
Yang mengatakan, benar-benar ada kasus penggunaan yang valid untuk melakukannya. Menentukan +path.prepend()
fungsi yang setara itu sepele. Sans prolix nebulosity, untuk kewarasannya bersama:
+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
}
Tapi ... Kenapa Tidak Gilles?
Gilles ' jawaban diterima di tempat lain optimal mengesankan dalam kasus umum sebagai 'shell agnostik idempoten append' . Dalam kasus umum bash
dan zsh
dengan tidak ada symlink yang tidak diinginkan, bagaimanapun, hukuman kinerja yang diperlukan untuk melakukannya sedih yang ricer Gentoo dalam diriku. Bahkan di hadapan symlink yang tidak diinginkan, masih diperdebatkan apakah forking satu subshell per add_to_PATH()
argumen bernilai potensi penyisipan duplikat symlink.
Untuk kasus penggunaan yang ketat yang menuntut duplikat symlink dihilangkan, zsh
varian khusus ini melakukannya melalui builtin yang efisien dan bukannya garpu yang tidak efisien:
+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
}
Perhatikan *":${dirname:A}:"*
bukan *":${dirname}:"*
yang asli. :A
adalah zsh
-ism yang luar biasa sayangnya tidak ada di bawah sebagian besar kerang lainnya - termasuk bash
. Mengutip man zshexpn
:
J : Ubah nama file menjadi jalur absolut seperti yang dilakukan a
pengubah, dan kemudian berikan hasilnya melalui realpath(3)
fungsi pustaka untuk menyelesaikan tautan simbolik. Catatan: pada sistem yang tidak memiliki realpath(3)
fungsi pustaka, tautan simbolik tidak terselesaikan, demikian juga pada sistem tersebut a
dan A
setara.
Tidak ada pertanyaan lebih lanjut.
Sama-sama. Nikmati penembakan yang aman. Anda sekarang layak menerimanya.