Unix, dosya sisteminde gezinirken bir kullanıcının çalışma dizinini nasıl takip eder?


29

Unix sistemindeki bir kabuğa giriş yaptığımı ve komutları bırakmaya başladığımı söyleyin. Başlangıçta, kullanıcının giriş dizininde başlıyorum ~. Oradan cddizine gidebilirim Documents.

Buradaki çalışma dizinini değiştirme komutu sezgisel olarak anlaşılması kolaydır: ana düğüm erişebileceği alt düğümlerin bir listesine sahiptir ve büyük olasılıkla bir alt düğümün varlığını bulmak için (optimize edilmiş) bir arama varyantı kullanır. girilen kullanıcıyı adlandırın ve çalışma dizini daha sonra buna uyması için "değiştirildi" - eğer yanlışysam beni düzeltin. Kabuğun basitçe "naif" bir şekilde dizine kullanıcının isteklerine göre tam olarak erişmeye çalışması daha kolay olabilir ve dosya sistemi bir tür hata verdiğinde, kabuk buna göre bir yanıt görüntüler.

Ancak ilgilendiğim şey, bir dizine, yani bir ebeveyne veya ebeveyin ebeveyni arasında gezinirken aynı işlemin nasıl çalıştığı.

Bilinmeyen, muhtemelen "kör" konumumun Documents, tüm dosya sistemi ağacında bu adı taşıyan birçok dizinden birinin bulunduğu göz önüne alındığında , Unix daha sonra nereye yerleştirilmem gerektiğini nasıl belirler? Buna referans veriyor pwdmu ve inceliyor mu? Eğer evet ise, pwdmevcut seyir durumunu nasıl takip ediyor?


Yanıtlar:


76

Diğer cevaplar, her biri hikayenin sadece bölümlerini sunan, aşırı basitleştirmelerdir ve birkaç noktada yanlıştır.

Çalışma dizininin izlendiği iki yol vardır :

  • Her işlem için, bu işlemi temsil eden çekirdek-alan veri yapısında, çekirdek, çalışma dizininin vnodlarına ve o işlemin kök dizinine iki vnode referansı depolar. Eski başvuru ile ayarlanır chdir()ve fchdir()sistem çağrıları, ikincisi chroot(). Bunları dolaylı /procolarak Linux işletim sistemlerinde ya da fstatFreeBSD ve benzeri komutlarla görebilirsiniz:

    % fstat -p $$ | head -n 5
    KULLANICI CMD PID FD MONTAJ MODELİ SZ | DV R / W
    JdeBP zsh 92648 metin / 24958 -r-xr-xr-x 702360 r
    JdeBP zsh 92648 ctty / dev 148 crw - w ---- puan / 4 rw
    JdeBP zsh 92648 wd / usr / ana sayfa / JdeBP 4 drwxr-xr-x 124 r
    JdeBP zsh 92648 kökü / 4 drwxr-xr-x 35 r
    % 

    Yol adı özünürlüğü çalıştığında, yolun göreceli veya mutlak olmasına bağlı olarak başvurulan vnotlardan biri veya diğerinden başlar. ( …at()Açık (dizin) dosya tanıtıcısının üçüncü bir seçenek olarak başvuru yaptığı vnode'da yol adı çözümlemesinin başlamasını sağlayan bir sistem çağrısı ailesi vardır .)

    Mikro çekirdek Unices'de veri yapısı uygulama alanındadır, ancak bu dizinlere açık referanslar tutma prensibi aynı kalmaktadır.

  • Dahili olarak, örneğin Z, Korn, Bourne Yine, C ve Almquist kabuk kabukları içinde, kabuk ek bir iç dize değişkeni dize işlemleri kullanarak çalışma dizini izler. Bunu, aramaya neden olduğu zaman yapar chdir().

    Biri göreceli bir yol adına değişirse, o ismi eklemek için dizgiyi değiştirir. Eğer biri mutlak yol ismine geçerse, dizeyi yeni isimle değiştirir. Her iki durumda da, dizeyi çıkarmak .ve ..bileşenleri kaldırmak ve onları bağlantılı isimleri ile değiştirmek yerine sembolik bağları kovalamak için ayarlar . ( Örneğin , Z kabuğunun bunun kodu .)

    İç string değişkenindeki isim, PWD(veya cwdC kabuklarında) isimli bir kabuk değişkeni ile izlenir . Bu, geleneksel olarak PWDkabuk tarafından oluşturulan programlara bir ortam değişkeni (adında ) olarak verilir.

İzleme şeylerin Bu iki yöntem ile ortaya çıkar -Pve -Lseçenekler cdve pwdkabuk dahili komutları ve yerleşik kabukları arasındaki farklılıklardan pwdkomutlar ve her iki /bin/pwdkomuta ve yerleşik pwdgibi şeylerin komutları (diğerleri arasında) VIM ve NeoVIM.

% mkdir a; 
% -sab % ( cdb ; pwd; / bin / pwd; printenv PWD)
/ Usr / home / JdeBP / b
/ Usr / home / JdeBP / a
/ Usr / home / JdeBP / b
% (cdb; pwd -P; / bin / pwd -P)
/ Usr / home / JdeBP / a
/ Usr / home / JdeBP / a
% (cdb; pwd-L; / bin / pwd -L)
/ Usr / home / JdeBP / b
/ Usr / home / JdeBP / b
% (cd-Pb; pwd; / bin / pwd; printenv PWD)
/ Usr / home / JdeBP / a
/ Usr / home / JdeBP / a
/ Usr / home / JdeBP / a
% (cd b; PWD = / merhaba / orada / bin / pwd -L)
/ Usr / home / JdeBP / a
% 

Gördüğünüz gibi: "mantıksal" çalışma dizinini edinmek, PWDkabuk değişkenine (ya da kabuk programı değilse çevre değişkeni) bakmaktan ibarettir; "fiziksel" çalışma dizinini edinmek ise getcwd()kitaplık işlevini çağırmaktan ibarettir.

Seçenek kullanıldığında /bin/pwdprogramın çalışması -Lbiraz incedir. Bu güvenemiyorum değerini PWDmiras ettiğini ortam değişkeni. Sonuçta, bir kabuk tarafından çağrılması gerekmedi ve araya giren programların kabuğun PWDçevre değişkenini her zaman çalışan dizinin adını izlemesini sağlayan mekanizma uygulamamış olabilir . Ya da biri orada yaptığımı yapabilir.

Öyleyse, (POSIX standardının dediği gibi) verilen PWDadın ., sistem çağrısı izlemesiyle görülebileceği gibi, adla aynı şeyi verdiğini kontrol edin :

% ln -sac 
% (cd b; truss / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd') 
stat ("/ usr / home / JdeBP / b", { mode = drwxr-xr-x, inode = 120932, size = 2, blksize = 131072}) = 0 (0x0) 
stat (".", {mode = drwxr-xr-x, inode = 120932, boyut = 2, blksize) = 131072)) = 0 (0x0)
/ Usr / home / JdeBP / b
% (cd b; PWD = / usr / yerel / etc truss / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd') 
stat ("/ usr / local / etc" , {mode = drwxr-xr-x, inode = 14835, size = 158, blksize = 10240}) = 0 (0x0) 
stat (".", {mode = drwxr-xr-x, inode = 120932, boyut = 2 , blksize = 131072}) = 0 (0x0)
__getcwd ("/ usr / home / JdeBP / a", 1024) = 0 (0x0)
/ Usr / home / JdeBP / a
% (cd b; PWD = / merhaba / truss / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd') 
stat ("/ hello / there", 0x7fffffffe730) ERR # 2 'Böyle bir dosya veya dizin yok' 
__getcwd ("/ usr / home / JdeBP / a", 1024) = 0 (0x0)
/ Usr / home / JdeBP / a
% (cd b; PWD = / usr / ana sayfa / JdeBP / c makas / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd') 
stat ("/ usr / home / JdeBP / c ", {mod = drwxr-xr-x, inode = 120932, boyut = 2, blksize = 131072}) = 0 (0x0) 
stat (". ", {Mode = drwxr-xr-x, inode = 120932 , size = 2, blksize = 131072}) = 0 (0x0)
/ Usr / home / JdeBP / c
%

Gördüğünüz gibi: yalnızca getcwd()bir uyuşmazlık tespit ederse çağırır ; ve PWDaslında aynı dizini adlandıran bir dize ayarlayarak , ancak farklı bir yolla kandırılabilir .

getcwd()Kütüphane işlevi kendi başına bir konudur. Ancak précis için:

  • Başlangıçta, çalışma dizinini, dizinde çalışma dizinini tekrar aramaya çalışarak kök dizinine kadar bir yol adı oluşturan tamamen bir kütüphane işlevidir ... ..Çalışma diziniyle aynı olan bir döngüye ulaştığında veya bir sonraki açmaya çalışırken bir hata olduğunda durdu ... Bu, kapakların altında bir çok sistem çağrısı olacaktır.
  • Günümüzde durum biraz daha karmaşık. FreeBSD üzerindeyken örneğin (bu aynı zamanda diğer işletim sistemleri için de geçerlidir olmak üzere), bu ise daha önce verilen sistem çağrısı izlemesinde görebileceğiniz gibi, gerçek bir sistem çağrısı. Çalışma dizini vnode'dan kök dizine kadar olan tüm geçiş tek bir sistem çağrısında yapılır; bu, çekirdek modu kodunun dizin adı önbelleğine doğrudan erişimi gibi şeylerden yararlanır;

    Ancak, FreeBSD ve diğer işletim sistemlerinde bile çekirdeğin çalışma dizini bir dizeyle takip etmediğini unutmayın .

Gezinmek ..yine kendi başına bir konudur. Başka bir yöntem: Dizinler geleneksel olarak (her ne kadar önceden belirtilmiş olsa da, zorunlu değildir ), her ne kadar ..diskteki dizin veri yapısında bir gerçek içeriyorsa da , çekirdek her dizinin vnode'sinin ana dizinini izler ve böylece ..herhangi bir dizinin içine gidebilir. çalışma dizini. Bu, bu cevabın kapsamı dışında olan bağlama noktası ve değişen kök mekanizmaları tarafından biraz karmaşıktır.

bir kenara

Windows NT aslında benzer bir şey yapar. SetCurrentDirectory()API çağrısı tarafından ayarlanan ve işlem başına çekirdeğin bu dizine (dahili) bir açık dosya tanıtıcısı aracılığıyla izlenen işlem başına tek bir çalışma dizini vardır; ve Win32 programlarının (yalnızca komut yorumlayıcıları değil, tüm Win32 programlarını da içeren) birden fazla çalışma dizininin (sürücü başına bir tane) isimlerini takip etmek için kullandıkları, her değiştirdiklerinde dizine ekleyen veya üzerine yazdıkları bir ortam değişkenleri kümesi vardır .

Geleneksel olarak, Unix ve Linux işletim sistemlerinde olduğu gibi, Win32 programları bu ortam değişkenlerini kullanıcılara göstermez. Bazen bunları Windows NT üzerinde çalışan Unix benzeri alt sistemlerde de görebilir, ancak komut yorumlayıcıların SETkomutlarını belirli bir şekilde kullanarak.

daha fazla okuma


1
Bu beklediğimden çok daha fazla. Teşekkürler ve daha fazla okuma için ekstra teşekkürler!
Reagular ToAngularVues

doc.cat-v.org/plan_9/4th_edition/papers/lexnames ilgili sorunlardan bazıları hakkında görüşmelere .., plan9 bağlamında
Icarus

@JdeBP: Belki bir şeyleri özlüyorum. ..., bash, ... ve ..., kabuk içinde sen, Dahili olarak”derler ayrıca bir iç dize değişkeni dize kullanımı kullanarak çalışma dizininin izler. …, Dizeyi çıkarmak .ve ..bileşenleri ayarlamak ve onları bağlanmış isimlerle değiştirmek yerine sembolik bağları kovalamak için ayarlar . … Dahili string değişkenindeki isim PWD… ” isimli bir kabuk değişkeni ile izlenir (vurgu eklenir). … (Devam ediyor)
G-Man

(Devamı) ... Ama senin örneğin gösterileri PWD= …/bbir sonraki cd bkomutu, olsa bile bsembolik link a- kabuk “peşine düşmek” değil böylece a -> bbağlantıyı. Yanlış mı yazdın yoksa yanlış mı söyledim?
G-Man

Basitçe bir yan noktadan parladım ve ayrıntılar için sizi kodun üzerine getirdim. Sembolik bağları ne zaman ve nasıl kovalamaya karar verdiklerine dair çeşitli mermilerin el kitaplarına bakın. Z kabuğu, karar formülünün bir parçası olan kabuk seçeneğini kolayca çağırır CHASE_LINKS.
JdeBP

1

Çekirdek, dizin veya dosya adlarını izlemez; bir dosya veya dizin çekirdekte bir inode / device pair tarafından temsil edilir. Gibi Sistem çağrıları chdir(), open()vb mutlak olabilir parametre olarak bir yol, (örn almak /etc/passwd) veya geçerli dizinine göre (örnekler: Documents, ..). Bir işlem yürütüldüğünde chdir("Documents"), Documentsgeçerli çalışma dizininde bir arama yapılır ve işlemin çalışma dizini bu dizine başvurmak üzere güncelleştirilir. Çekirdek perspektifinden bakıldığında, ".." adında özel bir şey yoktur, bu yalnızca dosya sisteminde ..ana dizine atıfta bulunan bir kongredir.

getcwd()İşlevi, bir sistem çağrısı, ama yolda yol bileşenlerinin isimleri kayıt kök dizinine yolunda kadar çalışmak zorunda kütüphane fonksiyonu değildir.


0

İlginçtir ki, geleneksel cd ..olarak çok daha basittir pwd. Adı ..verilen dizinler açıkça dosya sistemine yerleştirilir. Sistem, mevcut dizinin cihazını / inode'unu takip eder, bu yüzden cd ..veya daha doğrusu, sistem çağrısı chdir(".."), mevcut yönetmenin inode'una ait olan dosyadaki ".." adının aranmasını ve mevcut yönetmenin cihazını / inode'unu değiştirmeyi gerektirir. değer orada bulundu.

pwd(daha doğru bir şekilde /bin/pwd) ..art arda bağlantıları izler ve nereden geldiğini inode buluncaya kadar ilgili dizinleri okur, bu isimlerin listesini kök dizine ulaşana kadar (özellikle bir ..giriş içermeyen ) tersine çevirir .

Şimdi bu orijinal düşük seviyeli temel davranış. Gerçek kabuk komutları pwdbunun yerine mevcut yol adını önbelleğe alan çeşitli tekniklere dayanır. Fakat özünde, aslında bilinen tek inode'dur. Bu, bir kez sembolik bağlantılar dizinlerde gezinmek için kullanıldığında, mevcut kabuk ve sistemin mevcut çalışma dizini adı kavramlarının /bin/pwdfarklılaşabileceği anlamına gelir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.