Apakah ada cara untuk source
skrip shell ke namespace, lebih disukai skrip bash shell tapi saya akan melihat ke shell lain jika mereka memiliki fitur ini dan bash tidak.
Yang saya maksud dengan itu adalah, misalnya, sesuatu seperti "awalan semua simbol yang didefinisikan dengan sesuatu sehingga mereka tidak bertabrakan dengan simbol yang sudah didefinisikan (nama variabel, nama fungsi, alias)" atau fasilitas lain yang mencegah tabrakan nama.
Jika ada solusi di mana saya bisa namespace pada source
waktu ( NodeJS
gaya), itu akan menjadi yang terbaik.
Kode contoh:
$ echo 'hi(){ echo Hello, world; }' > english.sh
$ echo 'hi(){ echo Ahoj, světe; }' > czech.sh
$ . english.sh
$ hi
#=> Hello, world
$ . czech.sh #bash doesn't even warn me that `hi` is being overwritten here
$ hi
#=> Ahoj, světe
#Can't use the English hi now
#And sourcing the appropriate file before each invocation wouldn't be very efficient
( easiest thing ever )
. Tapi bukan itu yang Anda cari. Saya kira Anda bisa melakukan( stuff in subshell; exec env ) | sed 's/^/namespace_/'
daneval
hasilnya di shell induk tapi itu agak jahat.ksh93
. Namespaces sangat penting untuk itu - dan semua jenis namanya (yang juga dapat diketik) mendukung penempatan nama. Ngomongbash
-ngomong, ini juga jauh lebih cepat dalam segala hal daripada , omong-omong.env | sed ...
akan berfungsi untuk variabel, saya bisa lakukanset
untuk mendapatkan fungsi, tetapi pencarian dan penggantian akan menjadi masalah - fungsi dapat memanggil satu sama lain dan Anda sehingga Anda harus mengganti semua doa silang dengan doa silang yang diawali tetapi tanpa mengganti kata yang sama di tempat lain dalam kode definisi fungsi, di mana itu bukan doa. Untuk itu Anda memerlukan bash parser, bukan hanya regex, dan itu masih akan berfungsi selama fungsinya tidak saling memanggil melalui eval.Jawaban:
Dari
man ksh
pada sistem denganksh93
...Dan, untuk menunjukkan, inilah konsep yang diterapkan pada namespace yang disediakan secara default untuk setiap variabel shell biasa yang ditetapkan dalam
ksh93
shell. Dalam contoh berikut ini saya akan mendefinisikandiscipline
fungsi yang akan bertindak sebagai.get
metode yang ditugaskan untuk$PS1
variabel shell. Setiap variabel shell pada dasarnya mendapat namespace sendiri dengan, setidaknya, defaultget
,set
,append
, danunset
metode. Setelah mendefinisikan fungsi berikut, setiap kali variabel$PS1
direferensikan dalam shell, outputdate
akan ditarik di bagian atas layar ...(Perhatikan juga kurangnya
()
subkulit dalam substitusi perintah di atas)Secara teknis, ruang nama dan disiplin tidak persis sama (karena disiplin dapat didefinisikan untuk diterapkan baik secara global atau lokal ke ruang nama tertentu ) , tetapi keduanya merupakan bagian dan paket untuk konseptualisasi tipe data shell yang mendasar untuk
ksh93
.Untuk membahas contoh khusus Anda:
...atau...
sumber
Saya telah menulis fungsi shell POSIX yang dapat digunakan untuk lokal namespace sebuah builtin shell atau fungsi dalam salah
ksh93
,dash
,mksh
, ataubash
(bernama khusus karena saya secara pribadi telah dikonfirmasi untuk bekerja di semua ini) . Kerang tempat saya mengujinya, hanya gagal memenuhi harapan sayayash
, dan saya tidak pernah berharap itu bekerja sama sekalizsh
. Saya tidak mengujiposh
. Saya memberikan harapan untukposh
beberapa waktu yang lalu dan belum menginstalnya dalam beberapa waktu. Mungkin berhasil diposh
...?Saya mengatakan itu POSIX karena, dengan membaca spesifikasi saya, ia mengambil keuntungan dari perilaku tertentu dari utilitas dasar, tetapi, diakui, spesifikasinya tidak jelas dalam hal ini, dan, setidaknya satu orang tampaknya tidak setuju dengan saya. Secara umum saya memiliki ketidaksepakatan dengan yang satu ini. Saya akhirnya menemukan kesalahan itu menjadi kesalahan saya sendiri, dan mungkin saya juga salah saat ini mengenai spesifikasinya, tetapi ketika saya menanyainya lebih lanjut, dia tidak menjawab.
Namun, seperti yang saya katakan, ini benar-benar bekerja pada cangkang yang disebutkan di atas, dan pada dasarnya bekerja dengan cara berikut:
The
command
perintah ditetapkan sebagai utilitas pada dasarnya tersedia dan salah satu pra$PATH
'd builtin. Salah satu fungsi yang ditentukan adalah untuk membungkus utilitas builtin khusus di lingkungannya sendiri ketika memanggil mereka, dan ...... perilaku kedua penugasan baris perintah di atas sudah benar menurut spesifikasi. Perilaku kedua kondisi kesalahan ini juga benar, dan sebenarnya hampir sepenuhnya diduplikasi dari spesifikasi. Penugasan yang diawali dengan baris perintah fungsi atau bawaan khusus ditentukan untuk mempengaruhi lingkungan shell saat ini. Demikian juga, kesalahan pengalihan ditentukan sebagai fatal ketika menunjuk salah satu dari mereka.
command
dispesifikasikan untuk menekan perlakuan khusus dari builtin khusus dalam kasus tersebut, dan kasus redirection sebenarnya ditunjukkan dengan contoh dalam spesifikasi.Dibangun secara teratur, seperti
command
, di sisi lain, ditetapkan untuk berjalan di lingkungan subkulit - yang tidak berarti bahwa proses lain , hanya saja itu harus secara fundamental tidak dapat dibedakan dari satu. Hasil memanggil builtin biasa harus selalu menyerupai apa yang mungkin diperoleh dari perintah yang sama mampu$PATH
. Dan sebagainya...Tetapi
command
perintah tidak dapat memanggil fungsi shell, dan karena itu tidak dapat digunakan untuk membuat file perlakuan khusus mereka seperti untuk builtin biasa. Itu juga spec'd. Bahkan, spek mengatakan bahwa utilitas utamacommand
adalah bahwa Anda dapat menggunakannya dalam fungsi shell wrapper bernama untuk perintah lain untuk memanggil perintah lain tanpa rekursi diri karena tidak akan memanggil fungsi. Seperti ini:Jika Anda tidak menggunakan di
command
sanacd
fungsi hampir pasti akan segfault untuk rekursi diri.Tetapi sebagai builtin biasa yang dapat memanggil builtin khusus
command
dapat melakukannya dalam lingkungan subkulit . Dan, sementara saat ini shell-negara didefinisikan dalam kekuatan tongkat ke shell saat ini - tenturead
's$var1
dan$var2
melakukan - setidaknya hasil mendefinisikan baris perintah mungkin tidak harus ...Sekarang apakah atau tidak
command
kemampuan untuk menjadi builtin biasa dan langsung memanggil builtin khusus hanyalah semacam celah tak terduga berkenaan dengan baris perintah mendefinisikan saya tidak tahu, tapi saya tahu bahwa setidaknya empat shell sudah disebutkan untuk menghormaticommand
namespace.Dan meskipun
command
tidak dapat secara langsung memanggil fungsi shell, ia dapat memanggileval
seperti yang ditunjukkan, dan dapat melakukannya secara tidak langsung. Jadi saya membangun pembungkus namespace pada konsep ini. Dibutuhkan daftar argumen seperti:... kecuali bahwa
command
kata di atas hanya dikenali sebagai satu jika dapat ditemukan dengan kosong$PATH
. Selain lokal scoping variabel shell bernama pada baris perintah, juga secara lokal-scopes semua variabel dengan single-huruf kecil nama abjad dan daftar yang standar lainnya, seperti$PS3
,$PS4
,$OPTARG
,$OPTIND
,$IFS
,$PATH
,$PWD
,$OLDPWD
dan beberapa orang lain.Dan ya, dengan melakukan scoping
$PWD
dan$OLDPWD
variabel secara lokal dan kemudian secara eksplisitcd
ke$OLDPWD
dan$PWD
itu bisa cukup andal lingkup direktori kerja saat ini juga. Ini tidak dijamin, meskipun itu berusaha sangat keras. Itu mempertahankan deskriptor untuk7<.
dan ketika target bungkusnya mengembalikannyacd -P /dev/fd/7/
. Jika direktori kerja saat ini telahunlink()
di sementara, itu masih harus setidaknya berhasil mengubah kembali ke dalamnya tetapi akan memunculkan kesalahan buruk dalam kasus itu. Dan karena ia mempertahankan deskriptor, saya tidak berpikir kernel waras harus membiarkan perangkat root-nya di-unmount juga (???) .Itu juga secara lokal cakupan opsi shell, dan mengembalikan ini ke keadaan di mana ia menemukan mereka ketika utilitas dibungkus kembali. Ini memperlakukan
$OPTS
secara khusus karena ia memelihara salinan dalam ruang lingkupnya sendiri yang pada awalnya memberikan nilai$-
. Setelah juga menangani semua tugas pada command-line, ia akan melakukanset -$OPTS
tepat sebelum memanggil target wrap-nya. Dengan cara ini jika Anda mendefinisikan-$OPTS
pada command-line Anda dapat menentukan opsi shell target wrap Anda. Ketika target kembali, ia akanset +$- -$OPTS
dengan salinannya sendiri$OPTS
(yang tidak terpengaruh oleh baris perintah yang ditentukan) dan mengembalikan semua ke keadaan semula.Tentu saja, tidak ada yang menghentikan penelepon dari entah bagaimana secara eksplisit
returrn
keluar dari fungsi dengan cara membungkus target atau argumennya. Melakukan hal itu akan mencegah pemulihan / pembersihan negara yang akan dicoba.Untuk melakukan semua itu perlu
eval
mendalam tiga . Pertama ia membungkus dirinya sendiri dalam lingkup lokal, kemudian, dari dalam, ia membaca dalam argumen, memvalidasi mereka untuk nama shell yang valid, dan berhenti dengan kesalahan jika menemukan yang tidak. Jika semua argumen valid dan akhirnya salah satu penyebabcommand -v "$1"
untuk mengembalikan true (recall:$PATH
is kosong pada titik ini) itu akaneval
baris perintah mendefinisikan dan meneruskan semua argumen yang tersisa ke target wrap (meskipun mengabaikan kasus khusus untukns
- karena itu tidak akan akan sangat berguna, daneval
kedalaman tiga lebih dari cukup dalam) .Ini pada dasarnya bekerja seperti ini:
Ada beberapa pengalihan lain dan, dan beberapa tes yang aneh dilakukan dengan cara beberapa kerang dimasukkan
c
dalam$-
dan kemudian menolak untuk menerimanya sebagai pilihan untukset
(???) , tapi semua pendukung, dan terutama digunakan hanya untuk menyelamatkan dari memancarkan output yang tidak diinginkan dan serupa dalam kasus tepi. Dan begitulah cara kerjanya. Ia dapat melakukan hal-hal itu karena ia mengatur ruang lingkup lokalnya sendiri sebelum memanggil utilitas terbungkusnya dalam bentuk bersarang.Ini lama, karena saya mencoba untuk sangat berhati-hati di sini - tiga
evals
sulit. Tetapi dengan itu Anda bisa melakukannya:Melangkah lebih jauh dan terus-menerus menamakan ruang lingkup lokal dari utilitas yang dibungkus seharusnya tidak terlalu sulit. Dan bahkan seperti yang tertulis itu sudah mendefinisikan
$LOCALS
variabel ke utilitas terbungkus yang hanya terdiri dari daftar semua nama yang dipisahkan ruang yang didefinisikan dalam lingkungan utilitas terbungkus.Suka:
... yang benar-benar aman -
$IFS
telah disanitasi ke nilai standarnya dan hanya nama shell yang valid yang membuatnya$LOCALS
kecuali Anda menyetelnya sendiri di baris perintah. Dan bahkan jika mungkin ada karakter gumpalan dalam variabel split, Anda bisa mengaturOPTS=f
pada command-line juga untuk utilitas yang dibungkus untuk melarang ekspansi mereka. Bagaimanapun:Dan inilah fungsinya. Semua perintah diawali dengan /
\
untuk menghindarialias
ekspansi:sumber