Geçerli dizinde - veya kabuk komut dosyasını yürüttüğünüz dizinde - yürütmek için izin almanız şartıyla, tüm ihtiyacınız olan bir dizine mutlak bir yol istiyorsanız cd
.
Adım 10 cd
bireyin spec
Eğer -P
seçenek etkin, $PWD
ortam değişkeni tarafından çıkış olacaktır dizeye ayarlanır edilecektir pwd -P
. Geçerli çalışma dizinini belirlemek için yeni dizinde veya bu dizinin herhangi bir üstünde yeterli izin yoksa, $PWD
ortam değişkeninin değeri belirtilmez.
Ve üzerinde pwd -P
Standart çıktıya yazılan yol adı, sembolik bağlantı tipi dosyalara atıfta bulunan hiçbir bileşen içermemelidir. pwd
Yardımcı programın standart çıktıya yazabileceği birden fazla yol varsa , biri tek / eğik çizgi karakteriyle, diğeri iki veya eğik çizgi karakteriyle başlıyorsa, o zaman tek / eğik çizgi karakteriyle başlayan yol adını yazmalıdır. Yol adı, bir veya iki satır / eğik çizgi karakterinden sonra gereksiz / eğik çizgi içermemelidir.
Çünkü bu cd -P
ne Geçerli çalışma dizini ayarlamak zorundadır pwd -P
aksi yazdırmalısınız ve o cd -
yazdırmak zorunda $OLDPWD
olduğunu şu işleri:
mkdir ./dir
ln -s ./dir ./ln
cd ./ln ; cd . ; cd -
ÇIKTI
/home/mikeserv/test/ln
Bunun için bekle...
cd -P . ; cd . ; cd -
ÇIKTI
/home/mikeserv/test/dir
Ve yazdırdığımda da cd -
baskı yapıyorum $OLDPWD
. cd
setleri $PWD
yakında kadar cd -P .
$PWD
mutlak yolu artık /
ben başka değişkenleri gerekmez -. Ve aslında, izlemeye bile ihtiyacım olmamalı, .
ancak süslenmemişken etkileşimli bir kabuğa sıfırlama $PWD
konusunda belirli bir davranış var . Bu yüzden sadece geliştirmek için iyi bir alışkanlık.$HOME
cd
Bu yüzden, sadece yukarıdakileri yolda yapmak, yolunu ${0%/*}
doğrulamak için fazlasıyla yeterli olmalıdır $0
, ancak $0
yumuşak bir link olması durumunda, muhtemelen dizini değiştiremezsiniz, ne yazık ki.
İşte bunu idare edecek bir fonksiyon:
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
}
Geçerli kabukta yapabileceği kadarını yapmaya çalışır - bir alt kabuk çağırmadan - hatalara ve alt dizinlere işaret etmeyen yumuşak bağlantılara çağrılan alt kabuklar olsa da. POSIX uyumlu bir kabuğa, POSIX uyumlu ls
ve temiz bir _function()
ad alanına bağlıdır. Bu durumda hala geçerli olmaz, ancak unset
bu durumda bazı mevcut kabuğun işlevlerinin üzerine yazabilir . Genel olarak, tüm bu bağımlılıklar bir Unix makinesinde oldukça güvenilir bir şekilde bulunmalıdır.
Argümanlarla veya argümanlar olmadan çağrılan ilk şey $PWD
, kanonik değerine sıfırlanır - buradaki hedeflerine gereken bağlantıları gerektiği gibi çözer. Argümanlar olmadan denir ve bu konuda; ancak onlarla çağrılır ve her biri için yolu çözer ve kurallara uygun hale getirir ya da stderr
neden olmasın diye bir mesaj yazdırır .
Çoğunlukla mevcut kabukta çalıştığı için, herhangi bir uzunlukta bir argüman listesiyle başa çıkabilmesi gerekir. Aynı zamanda $_zdlm
değişkeni de ( unset
içinden geçtiğinde de gelir) arar ve C-kaçan değerini hemen her birinin tek bir \n
satır sonu karakteri ile takip ettiği argümanlarının her birinin hemen sağına yazdırır.
Çok fazla dizin değiştirme işlemi gerçekleştirir, ancak, onu kanonik değerine ayarlamaktan başka, etkilenmez $PWD
, ancak $OLDPWD
hiçbir zaman esasında sayılmaz.
Her argümanından olabildiğince kısa sürede vazgeçmeye çalışır. Bu ilk çalışır cd
içine $1
. Mümkünse, argümanın kanonik yolunu yazdırır stdout
. Yapamıyorsa, $1
var olup olmadığını kontrol eder ve yumuşak bir bağlantı değildir. Eğer doğruysa yazdırır.
Bu şekilde $1
, bir dizine işaret etmeyen sembolik bir bağlantı olmadığı sürece , kabuğun ele alma izni olan herhangi bir dosya tipi argümanını ele alır . Bu durumda while
bir alt kabuktaki döngü çağırır .
ls
Bağlantıyı okumak için çağırır . Herhangi bir referans yolunu güvenilir bir şekilde ele almak için ilk önce geçerli dizinin başlangıç değeriyle değiştirilmesi gerekir ve bu nedenle, komut değiştirme alt kabuğunda işlev aşağıdakileri yapar:
cd -...ls...echo /
ls
Bağlantının adını ve dizesini tam olarak içermesi gerektiği kadar çıktısının solundan çıkarır ->
. Ben ilk kaçınmak çalıştık de ile bunu yaparken shift
ve $IFS
çıkıyor bu gibi bicimlendirebilirim yakın olarak en güvenilir yöntemdir. Bu, Gilles'in poor_mans_readlink'in yaptığı şeydir - ve iyi yapılır.
Dönen dosya ls
kesinlikle yumuşak bir bağlantı olmadan bu işlemi bir döngüde tekrarlayacaktır . Bu noktada, o yolu daha önce olduğu gibi onaylar ve cd
ardından yazdırır.
Örnek kullanım:
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 \
. ..
ÇIKTI
/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/
Ya da muhtemelen ...
ls
dir/ file file? folder/ link@ ln@ script* script3@ script4@
zdlm=\\0 zpath * | cat -A
ÇIKTI
/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' -> ...