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 cdbireyin spec
Eğer -Pseçenek etkin, $PWDortam 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, $PWDortam 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. pwdYardı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 -Pne Geçerli çalışma dizini ayarlamak zorundadır pwd -Paksi yazdırmalısınız ve o cd -yazdırmak zorunda $OLDPWDolduğ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. cdsetleri $PWDyakında kadar cd -P . $PWDmutlak 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 $PWDkonusunda belirli bir davranış var . Bu yüzden sadece geliştirmek için iyi bir alışkanlık.$HOMEcd
Bu yüzden, sadece yukarıdakileri yolda yapmak, yolunu ${0%/*}doğrulamak için fazlasıyla yeterli olmalıdır $0, ancak $0yumuş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 lsve temiz bir _function()ad alanına bağlıdır. Bu durumda hala geçerli olmaz, ancak unsetbu 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 stderrneden 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 $_zdlmdeğişkeni de ( unsetiçinden geçtiğinde de gelir) arar ve C-kaçan değerini hemen her birinin tek bir \nsatı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 $OLDPWDhiçbir zaman esasında sayılmaz.
Her argümanından olabildiğince kısa sürede vazgeçmeye çalışır. Bu ilk çalışır cdiçine $1. Mümkünse, argümanın kanonik yolunu yazdırır stdout. Yapamıyorsa, $1var 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 whilebir alt kabuktaki döngü çağırır .
lsBağ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 /
lsBağ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 shiftve $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 lskesinlikle 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 cdardı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' -> ...