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
spesifikasi
Jika -P
opsi ini berlaku, $PWD
variabel lingkungan harus diatur ke string yang akan dihasilkan oleh pwd -P
. Jika ada cukup izin pada direktori baru, atau pada induk dari direktori itu, untuk menentukan direktori kerja saat ini, nilai $PWD
variabel lingkungan tidak ditentukan.
Dan terus pwd -P
Pathname yang ditulis ke output standar tidak boleh mengandung komponen apa pun yang merujuk pada file dari tautan simbolik tipe. Jika ada beberapa nama path yang pwd
dapat ditulis utilitas ke output standar, satu dimulai dengan karakter tunggal / slash dan satu atau lebih dimulai dengan dua karakter / slash, maka itu akan menulis nama path yang dimulai dengan karakter single / slash. Pathname tidak boleh mengandung karakter slash / karakter slash yang tidak perlu setelah satu atau dua karakter slash.
Itu karena cd -P
harus mengatur direktori kerja saat ini untuk apa yang pwd -P
seharusnya dicetak dan yang cd -
harus mencetak $OLDPWD
bahwa berikut berfungsi:
mkdir ./dir
ln -s ./dir ./ln
cd ./ln ; cd . ; cd -
KELUARAN
/home/mikeserv/test/ln
menunggu untuk itu...
cd -P . ; cd . ; cd -
KELUARAN
/home/mikeserv/test/dir
Dan ketika saya mencetak dengan cd -
saya mencetak $OLDPWD
. cd
set $PWD
segera setelah saya cd -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 ketika cd
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:
zpath() { cd -P . || return
_out() { printf "%s$_zdlm\n" "$PWD/${1##*/}"; }
_cd() { cd -P "$1" ; } >/dev/null 2>&1
while [ $# -gt 0 ] && _cd .
do if _cd "$1"
then _out
elif ! [ -L "$1" ] && [ -e "$1" ]
then _cd "${1%/*}"; _out "$1"
elif [ -L "$1" ]
then ( while set -- "${1%?/}"; _cd "${1%/*}"; [ -L "${1##*/}" ]
do set " $1" "$(_cd -; ls -nd -- "$1"; echo /)"
set -- "${2#*"$1" -> }"
done; _out "$1"
); else ( PS4=ERR:\ NO_SUCH_PATH; set -x; : "$1" )
fi; _cd -; shift; done
unset -f _out _cd; unset -v _zdlm
}
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 menimpa unset
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 pesan stderr
mengapa tidak
Karena sebagian besar beroperasi di shell saat ini, ia harus dapat menangani daftar argumen dengan panjang berapa pun. Itu juga mencari $_zdlm
variabel (yang juga unset
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 untuk stdout
. 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 memanggil while
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:
cd -...ls...echo /
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 dengan shift
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 dengan cd
kemudian dicetak.
Contoh penggunaan:
zpath \
/tmp/script \ #symlink to $HOME/test/dir/script.sh
ln \ #symlink to ./dir/
ln/nl \ #symlink to ../..
/dev/fd/0 \ #currently a here-document like : dash <<\HD
/dev/fd/1 \ #(zlink) | dash
file \ #regular file
doesntexist \ #doesnt exist
/dev/disk/by-path/pci-0000:00:16.2-usb-0:3:1.0-scsi-0:0:0:0 \
/dev/./././././././null \
. ..
KELUARAN
/home/mikeserv/test/dir/script.sh
/home/mikeserv/test/dir/
/home/mikeserv/test/
/tmp/zshtpKRVx (deleted)
/proc/17420/fd/pipe:[1782312]
/home/mikeserv/test/file
ERR: NO_SUCH_PATH: doesntexist
/dev/sdd
/dev/null
/home/mikeserv/test/
/home/mikeserv/
Atau mungkin ...
ls
dir/ file file? folder/ link@ ln@ script* script3@ script4@
zdlm=\\0 zpath * | cat -A
KELUARAN
/home/mikeserv/test/dir/^@$
/home/mikeserv/test/file^@$
/home/mikeserv/test/file$
^@$
/home/mikeserv/test/folder/^@$
/home/mikeserv/test/file$ #'link' -> 'file\n'
^@$
/home/mikeserv/test/dir/^@$ #'ln' -> './dir'
/home/mikeserv/test/script^@$
/home/mikeserv/test/dir/script.sh^@$ #'script3' -> './dir/script.sh'
/home/mikeserv/test/dir/script.sh^@$ #'script4' -> '/tmp/script' -> ...