Patrice, sorunun cevabındaki kaynağını tanımladı , fakat oradan neden aldığına oradan nasıl gidileceğini bilmek istiyorsan, işte uzun hikaye.
Bir işlemin şu andaki çalışma dizini, çok karmaşık olduğunu düşüneceğiniz bir şey değildir. Göreceli yolların (işlem tarafından yapılan sistem çağrılarında) başlayacağı türdeki bir dizine bir dosya tanıtıcısı olan işlemin bir özniteliğidir. Göreceli bir yolu çözerken, çekirdeğin o geçerli dizinin (a) tam yolunu bilmesi gerekmez, sadece göreceli yolun ilk bileşenini bulmak için bu dizin dosyasındaki dizin girişlerini okur (ve ..
diğerleri gibi) Bu konuda dosya) ve oradan devam ediyor.
Şimdi, bir kullanıcı olarak, bazen bu dizinin dizin ağacının neresinde olduğunu bilmek istersiniz. Çoğu Unices ile, dizin ağacı döngü içermeyen bir ağaçtır. Yani, ağacın kökünden ( /
) herhangi bir dosyaya giden tek bir yol var . Bu yol genellikle kanonik yol olarak adlandırılır.
Geçerli çalışma dizininin yolunu bulmak için, bir işlemin yapması gereken şey sadece yukarı yürümek ( aşağıdan köküne sahip bir ağaç görmek isterseniz aşağı doğru) ağaç köke geri dönerek düğümlerin adlarını bulmaktır. yolda.
Örneğin, geçerli dizinin olduğunu bulmaya çalışan bir işlem /a/b/c
, ..
dizini açar (göreceli yol, ..
geçerli dizindeki girdidir) ve aynı inode numarasına sahip bir tür dizini dosyası arar .
, c
eşleşir, sonra açılır ../..
ve bulana kadar devam eder /
. Orada belirsizlik yok.
Yani ne getwd()
ya getcwd()
C fonksiyonları yapmak ya da en azından yapardı.
Modern Linux gibi bazı sistemlerde, kanonik yolu çekirdek dizinde araştıran geçerli dizine döndürmek için bir sistem çağrısı vardır (ve tüm bileşenlerine okuma erişimi olmasa bile, geçerli dizini bulmanızı sağlar) ve getcwd()
orada öyle diyor. Modern Linux'ta, geçerli dizine giden yolu bir readlink () aracılığıyla da bulabilirsiniz /proc/self/cwd
.
Bu, çoğu dilin ve ilk kabukların, yolu geçerli dizine döndürürken yaptığı şeydir.
Sizin durumunuzda, Arayabileceğin cd a
istediğiniz gibi bir sembolik çünkü, may olarak kez .
geçerli dizin böylece tüm değişmez getcwd()
, pwd -P
, python -c 'import os; print os.getcwd()'
, perl -MPOSIX -le 'print getcwd'
senin dönecekti ${HOME}
.
Şimdi, sembolikler bütün bunları karmaşıklaştırmaya başladı.
symlinks
dizin ağacında atlamalara izin ver. Gelen /a/b/c
, eğer /a
ya /a/b
ya /a/b/c
sonra kurallı yolu bir sembolik olduğu /a/b/c
tamamen farklı bir şey olurdu. Özellikle, ..
giriş /a/b/c
mutlaka gerekli değildir /a/b
.
Bourne kabuğunda, eğer yaparsanız:
cd /a/b/c
cd ..
Ya da:
cd /a/b/c/..
Sonunda geleceğin garantisi yok /a/b
.
Aynen gibi:
vi /a/b/c/../d
mutlaka aynı değildir:
vi /a/b/d
ksh
Bir şekilde bunun üzerinde çalışmak için bir mantıksal güncel çalışma dizini kavramı ortaya koydu. İnsanlar buna alıştı ve POSIX, bugünlerde çoğu mermi anlamına gelen davranışların bunu yaptığını belirterek sona erdi:
İçin cd
ve pwd
(yerleşik komutların ve sadece onlar için (ayrıca yönelik olsa popd
/ pushd
onları) sahip kabukları üzerine), kabuk bulunulan dizinin kendi fikrini korur. $PWD
Özel değişkende saklanır .
Ne zaman yaparsın:
cd c/d
olsa bile c
ya c/d
da, sembolik bağlar olurlar $PWD
bidonlara /a/b
, bu ekler c/d
sonu öylesine için $PWD
olur /a/b/c/d
. Ve ne zaman:
cd ../e
Yapmak yerine chdir("../e")
yapar chdir("/a/b/c/e")
.
Ve pwd
komut sadece $PWD
değişkenin içeriğini döndürür .
Çünkü interaktif kabuklarda yararlıdır pwd
oraya nasıl hakkında bilgi verir ve sürece sadece kullandıkça geçerli dizine bir yolunu çıkarır ..
için argüman olarak cd
ve diğer değil komutlar, bu size sürpriz olasılığı düşüktür, çünkü cd a; cd ..
ya cd a/..
olur genelde size geri almak olduğun yere.
Şimdi, $PWD
bir yapmadıkça değiştirilmez cd
. Bir dahaki sefere cd
ya da pwd
bir çok şey olabilir, bileşenlerinin herhangi biri $PWD
yeniden adlandırılabilir. Geçerli dizin asla değişmez (silinmesine rağmen her zaman aynı inode'dur), ancak dizin ağacındaki yolu tamamen değişebilir. getcwd()
geçerli dizini her seferinde dizin ağacından aşağıya doğru yürüterek hesaplar, böylece bilgileri her zaman doğrudur, ancak POSIX kabukları tarafından uygulanan mantıksal dizin için, içerdiği bilgiler $PWD
eski olabilir. Yani koşarken cd
ya da pwd
bazı mermiler buna karşı korunmak isteyebilir.
Bu özel durumda, farklı mermilerle farklı davranışlar görüyorsunuz.
Bazıları ksh93
sorunu tamamen görmezden gelir, bu yüzden aradıktan sonra bile yanlış bilgi döndürür cd
(ve bash
orada gördüğünüz davranışı görmezsiniz ).
Gibi bazı bash
veya zsh
kontrol yapmak $PWD
hala üzerine geçerli dizine bir yol olduğunu cd
ancak üzerine pwd
.
pdksh her ikisini de kontrol eder pwd
ve cd
(ancak pwd
güncelleme yapmaz $PWD
)
ash
(en azından Debian üzerinde bulunan bir) kontrol etmez, ve bunu yaparken cd a
, bu gerçekten oluyor cd "$PWD/a"
geçerli dizin değişti ve eğer öyleyse, $PWD
geçerli dizine artık puan, aslında hiç değişmeyecek a
geçerli dizinde dizinde , ancak bir tane $PWD
(ve yoksa bir hata döndür).
Onunla oynamak istiyorsanız, şunları yapabilirsiniz:
cd
mkdir -p a/b
cd a
pwd
mv ~/a ~/b
pwd
echo "$PWD"
cd b
pwd; echo "$PWD"; pwd -P # (and notice the bug in ksh93)
çeşitli kabuklarda.
Sizin durumunuzda, kullandığınızdan beri , a'dan bash
sonra hala geçerli dizine işaret eden kontroller . Bunu yapmak için, inode numarasını kontrol etmek ve onunkiyle karşılaştırmak için değerini çağırır .cd a
bash
$PWD
stat()
$PWD
.
Kadar bakarken Ama $PWD
yolu bu, çok fazla sembolik çözme içerir stat()
bir hata ile döner, böylece kabuk olmadığı kontrol edilemiyor $PWD
hala geçerli dizine karşılık, bu yüzden birlikte tekrar bir hesaplar getcwd()
ve güncellemeler $PWD
buna göre.
Şimdi, Patrice'in cevabını açıklığa kavuşturmak için, bir yol ararken karşılaşılan sembolik bağlantıların kontrolünün sembolik bağlantı halkalarına karşı korunma sağlanmasıdır. En basit döngü ile yapılabilir
rm -f a b
ln -s a b
ln -s b a
Bu güvenlik görevlisi olmasaydı, bir cd a/x
sistem üzerine , a
bağlantıların nerede olduğunu bulması , bulması b
ve bulduğu bağlantıyı bulması ve a
süresiz olarak devam etmesi gerekirdi. Buna karşı korunmanın en basit yolu, rastgele sayıda sembolik işaretten fazlasını çözdükten sonra pes etmektir.
Şimdi mantıksal çalışma dizinine geri dönelim ve neden bu kadar iyi bir özellik değil. Bunun sadece cd
kabuğun içinde olduğunu ve diğer komutların olmadığını fark etmek önemlidir .
Örneğin:
cd -- "$dir" && vi -- "$file"
her zaman aynı değildir:
vi -- "$dir/$file"
Bu nedenle, bazen insanların cd -P
kafa karışıklığını önlemek için komut dosyalarında her zaman kullanılmasını önerdiğini anlarsınız ( ../x
yalnızca başka bir dilin yerine kabuğa yazılmış olduğundan yazılımınızın diğer komutlardan farklı bir argümanı ele almasını istemezsiniz ).
-P
Seçenek devre dışı bırakmaktır mantıksal dizin böylece taşıma cd -P -- "$var"
sesleniyor aslında chdir()
içeriğine $var
(dışında $var
olduğunu -
bu başka bir hikaye ama). Ve bir sonraki cd -P
, $PWD
bir kanonik yolunu içerecektir.