他の答えは単純化であり、それぞれがストーリーの一部のみを示しており、いくつかの点で間違っています。
作業ディレクトリを追跡する方法は2つあります。
- プロセスごとに、そのプロセスを表すカーネル空間データ構造に、カーネルはそのプロセスの作業ディレクトリとルートディレクトリのvnodeへの2つのvnode参照を格納します。前者の参照は
chdir()
とfchdir()
システムコールによって設定され、後者はによって設定されchroot()
ます。/proc
Linuxオペレーティングシステム上で間接的に、またはfstat
FreeBSDなどのコマンドを介して、それらを見ることができます。%fstat -p $$ | head -n 5
ユーザーCMD PID FDマウントINUMモードSZ | DV R / W
JdeBP ZSH 92648テキスト/ 24958 -r-xr-xr-x 702360 r
JdeBP zsh 92648 ctty / dev 148 crw--w ---- pts / 4 rw
JdeBP zsh 92648 wd / usr / home / JdeBP 4 drwxr-xr-x 124 r
JdeBP zsh 92648ルート/ 4 drwxr-xr-x 35 r
%
パス名の解決が機能する場合、パスが相対パスであるか絶対パスであるかに応じて、参照されるvnodeのいずれかで開始されます。(…at()
3番目のオプションとして、オープン(ディレクトリ)ファイル記述子によって参照されるvnodeでパス名の解決を開始できるシステムコールのファミリがあります。)
マイクロカーネルユニックスでは、データ構造はアプリケーションスペースにありますが、これらのディレクトリへのオープンリファレンスを保持する原理は同じままです。
- 内部的には、Z、Korn、Bourne Again、C、およびAlmquistシェルなどのシェル内で、シェルは内部文字列変数の文字列操作を使用して作業ディレクトリをさらに追跡します。呼び出す原因があるときはいつでもこれを行います
chdir()
。相対パス名に変更すると、文字列を操作してその名前を追加します。絶対パス名に変更すると、文字列が新しい名前に置き換えられます。どちらの場合も、削除する文字列.
と..
コンポーネントを調整し、シンボリックリンクを追跡してそれらをリンク先の名前に置き換えます。(たとえば、そのためのZシェルのコードは次のとおりです。)
内部文字列変数の名前は、(またはCシェルの)という名前のシェル変数によって追跡されます。これは従来、シェルによって生成されたプログラムに環境変数(という名前)としてエクスポートされます。PWD
cwd
PWD
物事を追跡するこれらの2つの方法は、シェル組み込みコマンドの-P
and -L
オプション、cd
およびpwd
シェルの組み込みpwd
コマンドと(特に)などの/bin/pwd
コマンドと組み込みコマンドの両方の違いによって明らかになります。pwd
VIMおよびNeoVIM。
%mkdir a; ln -sab
%(cd b; pwd; / bin / pwd; printenv PWD)
/ usr / home / JdeBP / b
/ usr / home / JdeBP / a
/ usr / home / JdeBP / b
%(cd b; pwd -P; / bin / pwd -P)
/ usr / home / JdeBP / a
/ usr / home / JdeBP / a
%(cd b; pwd -L; / bin / pwd -L)
/ usr / home / JdeBP / b
/ usr / home / JdeBP / b
%(cd -P b; pwd; / bin / pwd; printenv PWD)
/ usr / home / JdeBP / a
/ usr / home / JdeBP / a
/ usr / home / JdeBP / a
%(cd b; PWD = / hello / there / bin / pwd -L)
/ usr / home / JdeBP / a
%
ご覧のとおり、「論理」作業ディレクトリの取得は、PWD
シェル変数(またはシェルプログラムでない場合は環境変数)を調べるだけです。一方、「物理」作業ディレクトリを取得するには、getcwd()
ライブラリ関数を呼び出すだけです。
オプションが使用される/bin/pwd
ときのプログラムの動作-L
はやや微妙です。継承した環境変数の値を信頼することはできませんPWD
。結局のところ、シェルによって呼び出される必要はなく、介在するプログラムは、PWD
環境変数が常に作業ディレクトリの名前を追跡するようにするシェルのメカニズムを実装していない可能性があります。または、誰かが私がちょうどそこでしたことをするかもしれません。
そのため、システムコールトレースで見られるように、(POSIX規格が言うように)で指定さPWD
れた名前がnameと同じものを生成することを確認し.
ます:
%ln -sac
%(cd b;トラス/ 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、size = 2、blksize = 131072})= 0(0x0)
/ usr / home / JdeBP / b
%(cd b; PWD = / usr / local / 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、size = 2 、blksize = 131072})= 0(0x0)
__getcwd( "/ usr / home / JdeBP / a"、1024)= 0(0x0)
/ usr / home / JdeBP / a
%(cd b; PWD = / hello / there truss / bin / pwd -L 3>&1 1>&2 2>&3 | grep -E '^ stat | __getcwd')
stat( "/ hello / there"、0x7fffffffe730)ERR #2「そのようなファイルまたはディレクトリはありません」
__getcwd( "/ usr / home / JdeBP / a"、1024)= 0(0x0)
/ usr / home / JdeBP / a
%(cd b; PWD = / usr / home / JdeBP / c truss / bin / pwd -L 3>&1 1>&2 2>&3 | grep -E '^ stat | __getcwd')
stat( "/ usr / home / JdeBP / c "、{mode = drwxr-xr-x、inode = 120932、size = 2、blksize = 131072})= 0(0x0)
stat("。 "、{mode = drwxr-xr-x、inode = 120932 、size = 2、blksize = 131072})= 0(0x0)
/ usr / home / JdeBP / c
%
ご覧のとおりgetcwd()
、不一致を検出した場合にのみ呼び出します。また、PWD
実際には同じディレクトリに名前を付ける文字列に設定することで、別のルートでだまされる可能性があります。
getcwd()
ライブラリ関数は、それ自体で主題です。しかし、前に:
..
再びナビゲートすることは、それ自体が主題です。別の注意:従来のディレクトリ(既に言及したように、これは必須ではありませんが)には..
ディスク上のディレクトリデータ構造に実際のデータが含まれていますが、カーネルは各ディレクトリvnode自体の親ディレクトリを追跡するため、..
任意のvnodeにナビゲートできます作業ディレクトリ。これは、マウントポイントと変更されたルートメカニズムによって多少複雑になりますが、これはこの回答の範囲外です。
さておき
実際、Windows NTでも同様のことが行われます。プロセスごとに単一の作業ディレクトリがあり、SetCurrentDirectory()
API呼び出しによって設定され、そのディレクトリへの(内部)オープンファイルハンドルを介してカーネルによってプロセスごとに追跡されます。また、Win32プログラム(コマンドインタープリターだけでなく、すべての Win32プログラム)が複数の作業ディレクトリ(ドライブごとに1つ)の名前を追跡し、ディレクトリを変更するたびに追加または上書きするために使用する環境変数のセットがあります。
従来、UnixおよびLinuxオペレーティングシステムの場合とは異なり、Win32プログラムはこれらの環境変数をユーザーに表示しません。ただし、コマンドインタープリターのSET
コマンドを特定の方法で使用するだけでなく、Windows NTで実行されているUnixライクなサブシステムでそれらを見ることができます。
参考文献