Apa cara portabel untuk skrip (zsh) untuk menentukan jalur absolutnya?
Di Linux saya menggunakan sesuatu seperti
mypath=$(readlink -f $0)
... tapi ini tidak portabel. (Misalnya, readlink
pada darwin tidak mengenali -f
bendera, juga tidak memiliki yang setara.) (Juga, menggunakan readlink
untuk ini, memang, peretasan yang tampak tidak jelas.)
Apa cara yang lebih portabel?
Jawaban:
Dengan
zsh
, hanya saja:Sekarang untuk shell lain, meskipun
realpath()
danreadlink()
merupakan fungsi standar (yang terakhir menjadi panggilan sistem),realpath
danreadlink
bukan perintah standar, meskipun beberapa sistem memiliki satu atau yang lain atau keduanya dengan berbagai perilaku dan fitur yang ditetapkan.Seperti sering, untuk portabilitas, Anda mungkin ingin menggunakan
perl
:Itu akan berperilaku lebih seperti GNU
readlink -f
daripadarealpath()
(GNUreadlink -e
) dalam hal itu tidak akan mengeluh jika file tersebut tidak ada asalkan dirname tidak.sumber
.zshrc
: Lihat posting ini sebagai gantinya.Di zsh Anda dapat melakukan hal berikut:
Atau, untuk mendapatkan direktori tempat skrip berada:
Sumber: halaman manual zshexpn (1), bagian EKSPANSI SEJARAH, Pengubah ayat (atau sederhana
info -f zsh -n Modifiers
).sumber
readlink -f
lebih suka$0:A
.Saya telah menggunakan ini selama beberapa tahun sekarang:
sumber
readlink -f
adalah ketika skrip itu sendiri adalah symlink.zsh
, jika saya menjalankan ini baik secara langsung atau dalam subshell (seperti yang disarankan) saat di dir home saya (/home/ville
), ia mencetak/home/ville/zsh
.Sintaks ini harus portabel untuk setiap Bourne shell gaya interpreter (diuji dengan
bash
,ksh88
,ksh93
,zsh
,mksh
,dash
danbusybox sh
):Versi ini menambahkan kompatibilitas ke shell Bourne AT&T legacy (non POSIX):
sumber
$PWD
mungkin berlebihan - Anda bisa mengaturnya menjadi arus absolut seperticd -P .
. Saya ragu itu akan bekerja di bourneshell - tetapi harus bekerja di semua yang Anda uji untuk yang pertama. tetap melakukannya untuk saya.zsh
dandirname
tetapi dengan cepat menarik komentarnya ...Dengan asumsi Anda benar-benar berarti jalur absolut, yaitu jalur dari direktori root:
Ngomong-ngomong, ini bekerja di shell gaya Bourne.
Jika Anda maksud jalur dengan semua tautan simbolik diselesaikan, itu masalah yang berbeda.
readlink -f
bekerja di Linux (tidak termasuk beberapa sistem BusyBox yang dipreteli), FreeBSD, NetBSD, OpenBSD dan Cygwin, tetapi tidak pada OS / X, AIX, HP / UX atau Solaris. Jika sudahreadlink
, Anda bisa menyebutnya dalam satu lingkaran:Jika tidak punya
readlink
, Anda bisa memperkirakannya denganls -n
, tetapi ini hanya berfungsi jikals
tidak memotong-motong karakter yang tidak dapat dicetak dalam nama file.(Ekstra
z
dalam hal target tautan berakhir pada baris baru, yang substitusi perintahnya akan habis.realpath
Fungsi tidak menangani kasus itu untuk nama direktori, by the way.)sumber
ls
implementasi yang membuat karakter yang tidak dapat dicetak ketika output tidak pergi ke terminal.touch Stéphane; LC_ALL=C busybox ls Stéphane | cat
→St??phane
(jika namanya ada di UTF-8, latin1 memberi Anda satu?
). Saya pikir saya juga pernah melihatnya di Unives komersial yang lebih tua.busybox
ini? menurut gitbusybox ls
belum ada perubahan kode sejak 2011. Mybusybox ls
- sekitar 2013 - tidak melakukan hal ini. Ini satu - sekitar tahun 2012 - tidak . Ini mungkin menjelaskan mengapa. Sudahkah Anda membangunbusybox
dengan dukungan Unicode - untuk menyertakan dukungan wchar? Anda mungkin ingin mencobanya, lain untuk memeriksa opsi build dalammkinitcpio
busybox
paket.Asalkan Anda telah menjalankan izin pada direktori saat ini - atau pada direktori dari mana Anda mengeksekusi skrip shell Anda - jika Anda ingin jalur absolut ke direktori yang Anda butuhkan
cd
.Langkah 10 dari
cd
spesifikasiDan terus
pwd -P
Itu karena
cd -P
harus mengatur direktori kerja saat ini untuk apa yangpwd -P
seharusnya dicetak dan yangcd -
harus mencetak$OLDPWD
bahwa berikut berfungsi:KELUARAN
menunggu untuk itu...
KELUARAN
Dan ketika saya mencetak dengan
cd -
saya mencetak$OLDPWD
.cd
set$PWD
segera setelah sayacd -P .
$PWD
sekarang menjadi jalur absolut untuk/
- jadi saya tidak perlu variabel lain. Dan sebenarnya, saya bahkan tidak perlu membuntuti,.
tetapi ada perilaku pengaturan ulang yang ditentukan$PWD
ke$HOME
dalam shell interaktif ketikacd
tanpa hiasan. Jadi itu hanya kebiasaan yang baik untuk dikembangkan.Jadi hanya melakukan hal di atas pada jalur di
${0%/*}
harus lebih dari cukup untuk memverifikasi$0
path, tetapi dalam kasus itu$0
sendiri merupakan soft-link, Anda mungkin tidak dapat mengubah direktori ke dalamnya, sayangnya.Berikut adalah fungsi yang akan mengatasinya:
Ia berusaha keras untuk melakukan sebanyak mungkin dalam shell saat ini - tanpa menggunakan subkulit - meskipun ada subkulit yang dipanggil untuk kesalahan dan tautan lunak yang tidak mengarah ke direktori. Itu tergantung pada shell yang kompatibel dengan POSIX dan yang kompatibel
ls
dengan POSIX dan juga clean_function()
namespace yang . Ini masih akan berfungsi dengan baik tanpa yang terakhir, meskipun mungkin menimpaunset
beberapa fungsi shell saat ini dalam kasus itu. Secara umum semua dependensi ini harus cukup andal tersedia pada mesin Unix.Dipanggil dengan atau tanpa argumen, hal pertama yang dilakukannya adalah reset
$PWD
ke nilai kanoniknya - ia memutuskan semua tautan di dalamnya ke target mereka sebagaimana diperlukan. Disebut tanpa argumen dan hanya itu; tetapi dipanggil dengan mereka dan itu akan menyelesaikan dan mengkanonik jalur untuk masing-masing atau mencetak pesanstderr
mengapa tidakKarena sebagian besar beroperasi di shell saat ini, ia harus dapat menangani daftar argumen dengan panjang berapa pun. Itu juga mencari
$_zdlm
variabel (yang jugaunset
ketika itu melalui) dan mencetak nilai C-escaped langsung ke kanan setiap argumennya, yang masing-masing selalu diikuti juga oleh satu\n
karakter ewline .Itu tidak banyak direktori berubah, tapi, selain pengaturan ke nilai kanonik, itu tidak mempengaruhi
$PWD
, meskipun$OLDPWD
tidak dengan cara apa pun dapat diandalkan ketika sedang lewat.Ia mencoba untuk keluar dari setiap argumennya sesegera mungkin. Pertama kali mencoba
cd
masuk$1
. Jika itu bisa mencetak jalur kanonik argumen untukstdout
. Jika tidak dapat memeriksa apakah$1
ada dan bukan tautan lunak. Jika benar, itu akan dicetak.Dengan cara ini ia menangani argumen tipe file apa pun yang shell memiliki izin untuk mengatasinya kecuali
$1
tautan simbolis yang tidak mengarah ke direktori. Dalam hal ini ia memanggilwhile
loop dalam subkulit.Itu panggilan
ls
untuk membaca tautan. Direktori saat ini harus diubah ke nilai awalnya terlebih dahulu agar dapat menangani semua jalur referensi dengan andal, dan dalam substitusi perintah, subshell berfungsi:Itu strip dari kiri
ls
output sesedikit yang diperlukan untuk sepenuhnya berisi nama tautan dan string->
. Meskipun pada awalnya saya mencoba untuk menghindari melakukan ini denganshift
dan$IFS
ternyata ini adalah metode yang paling dapat diandalkan sedekat yang saya bisa. Ini adalah hal yang sama dengan poor_mans_readlink Gilles - dan ini dilakukan dengan baik.Ini akan mengulangi proses ini dalam satu lingkaran sampai nama file kembali dari
ls
jelas bukan tautan lunak. Pada titik itu kanonik jalur yang seperti sebelumnya dengancd
kemudian dicetak.Contoh penggunaan:
KELUARAN
Atau mungkin ...
KELUARAN
sumber
bagaimana dengan satu-liner simpatik ketika ada python tersedia untuk mencegah mendefinisikan ulang suatu algoritma?
sama seperti https://stackoverflow.com/a/7305217
sumber