UNIXシステムのシェルにログインし、コマンドをタップし始めたとします。最初はユーザーのホームディレクトリ~
から始めます 。そこからcd
Documents
ディレクトリまで 。
ここで作業ディレクトリを変更するコマンドは、直感的に理解するのが非常に簡単です。親ノードには、アクセスできる子ノードのリストがあり、おそらく、検索の(最適化された)バリアントを使用して、子ノードの存在を特定します。入力したユーザーに名前を付けると、作業ディレクトリがこれに一致するように「変更」されます。間違っている場合は修正してください。シェルが単に「素朴に」ユーザーの希望どおりにディレクトリへのアクセスを試み、ファイルシステムが何らかのエラーを返すと、それに応じてシェルが応答を表示する方が簡単な場合もあります。
ただし、私が興味を持っているのは、ディレクトリを上に移動したとき、つまり親または親の親に移動したときに同じプロセスがどのように機能するかです。
不明な、おそらく「ブラインド」の場所であるDocuments
、その名前のファイルシステムツリー全体にある可能性のある多くのディレクトリの1つですが、Unixは次に配置する場所をどのように決定しますか? pwd
を参照していますか? それを調べますか?はいの場合、pwd
はどのように機能しますか 現在のナビゲーション状態を追跡しますか?
承認された回答:
他の答えは過度に単純化されており、それぞれが物語の一部しか提示しておらず、いくつかの点で間違っています。
2つあります 作業ディレクトリを追跡する方法:
- すべてのプロセスについて、そのプロセスを表すカーネル空間データ構造で、カーネルは、そのプロセスの作業ディレクトリとルートディレクトリのvノードへの2つのvノード参照を格納します。前者の参照は
chdir()
によって設定されます およびfchdir()
システムコール、後者はchroot()
による 。/proc
で間接的に見ることができます Linuxオペレーティングシステムまたはfstat
経由 FreeBSDなどのコマンド:% fstat -p $$|head -n 5 USER CMD PID FD MOUNT INUM MODE SZ|DV R/W JdeBP zsh 92648 text / 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 root / 4 drwxr-xr-x 35 r %
パス名解決が機能する場合、パスが相対パスであるか絶対パスであるかに応じて、参照されているvnodeのいずれかで開始されます。 (
…at()
のファミリーがあります 3番目のオプションとして開いている(ディレクトリ)ファイル記述子によって参照されるvノードでパス名の解決を開始できるようにするシステムコール。)マイクロカーネルユニスでは、データ構造はアプリケーションスペースにありますが、これらのディレクトリへのオープン参照を保持する原則は同じです。
- 内部的には、Z、Korn、Bourne Again、C、Almquistシェルなどのシェル内で、シェルはさらに 内部文字列変数の文字列操作を使用して、作業ディレクトリを追跡します。
chdir()
を呼び出す原因がある場合は常にこれを行います 。相対パス名に変更すると、文字列を操作してその名前を追加します。絶対パス名に変更すると、文字列が新しい名前に置き換えられます。どちらの場合も、文字列を調整して
.
を削除します。 および..
コンポーネントと、それらをリンク先の名前に置き換えるシンボリックリンクを追跡します。 (たとえば、そのためのZシェルのコードは次のとおりです。)内部文字列変数の名前は、シェル変数によって追跡されます。 名前付き
PWD
(またはcwd
Cシェルで)。これは通常、環境変数(PWD
という名前)としてエクスポートされます。 )シェルによって生成されたプログラムに。
物事を追跡するこれらの2つの方法は、-P
によって明らかにされます。 および-L
cd
のオプション およびpwd
シェルの組み込みコマンド、およびシェルの組み込みのpwd
の違いによる コマンドと/bin/pwd
の両方 コマンドと組み込みのpwd
(とりわけ)VIMやNeoVIMのようなもののコマンド。
% mkdir a ; ln -s a b % (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 %関連:大きなファイルをサポートする代替GUIファイルエディタをお探しですか?
ご覧のとおり、「論理的な」作業ディレクトリを取得するには、PWD
を確認する必要があります。 シェル変数(またはシェルプログラムでない場合は環境変数)。一方、「物理的な」作業ディレクトリを取得するには、getcwd()
を呼び出します。 ライブラリ関数。
/bin/pwd
の操作 -L
の場合のプログラム 使用されるオプションはやや微妙です。 信頼できない PWD
の値 継承した環境変数。結局のところ、シェルによって呼び出される必要はなく、介在するプログラムがPWD
を作成するシェルのメカニズムを実装していない可能性があります。 環境変数は常に作業ディレクトリの名前を追跡します。または、誰かが私がそこでやったことをするかもしれません。
つまり、(POSIX標準で述べられているように)PWD
で指定された名前を確認します。 .
という名前と同じものが生成されます 、システムコールトレースでわかるように:
% ln -s a c % (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,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 'No such file or directory' __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()
ライブラリ関数はそれ自体が主題です。しかし、プレシスに:
- 元々は純粋にライブラリ関数であり、
..
で作業ディレクトリを繰り返し検索しようとすることで、作業ディレクトリからルートまでのパス名を作成していました。 ディレクトリ。..
のループに到達すると停止しました 作業ディレクトリと同じであるか、次の..
を開こうとしてエラーが発生したとき 上。これは、内部での多くのシステムコールになります。 - 現在、状況は少し複雑になっています。たとえば、FreeBSDでは(これは他のオペレーティングシステムにも当てはまります)、 前に示したシステムコールトレースでわかるように、真のシステムコール。作業ディレクトリvnodeからルートまでのすべてのトラバーサルは1回のシステムコールで実行されます。これは、カーネルモードコードがディレクトリエントリキャッシュに直接アクセスするなどの利点を利用して、パス名コンポーネントのルックアップをはるかに効率的に実行します。>
ただし、FreeBSDやその他のオペレーティングシステムでも、カーネルはしないことに注意してください。 文字列を使用して作業ディレクトリを追跡します。
..
に移動する 再びそれ自体が主題です。別のプレシス:ディレクトリは従来通りですが(すでに示唆されているように、これはではありません 必須)実際の..
が含まれている ディスク上のディレクトリデータ構造では、カーネルは各ディレクトリvnode自体の親ディレクトリを追跡するため、..
に移動できます。 任意の作業ディレクトリのvノード。これは、マウントポイントと変更されたルートメカニズムによって多少複雑になりますが、これらはこの回答の範囲を超えています。
脇
実際、WindowsNTも同様のことを行います。 SetCurrentDirectory()
によって設定された、プロセスごとに1つの作業ディレクトリがあります。 API呼び出しと、そのディレクトリへの(内部)オープンファイルハンドルを介したカーネルによるプロセスごとの追跡。 Win32がプログラムする環境変数のセットがあります(コマンドインタープリターだけでなく、すべて Win32プログラム)は、複数の作業ディレクトリ(ドライブごとに1つ)の名前を追跡し、ディレクトリを変更するたびにそれらを追加または上書きするために使用します。
従来、UnixおよびLinuxオペレーティングシステムの場合とは異なり、Win32プログラムはこれらの環境変数をユーザーに表示しません。ただし、Windows NTで実行されているUnixライクなサブシステムや、コマンドインタプリタのSET
を使用すると、それらを確認できる場合があります。 特定の方法でコマンドを実行します。
さらに読む
- 「
pwd
「。 OpenGroupベースの仕様 問題7。IEEE1003.1:2008。オープングループ。 2016年。 - 「パス名の解決」。 OpenGroupベースの仕様 問題7。IEEE1003.1:2008。オープングループ。 2016年。
- https://askubuntu.com/a/636001/43344
- UNIXではファイルはどのように開かれますか?
- FreeBSDまたはSolarisでのiノードの目的
- Cygwinの奇妙な環境変数!::=::
- マニュアルに記載されているようにCDPATHが機能しないのはなぜですか?
- 物理パスを使用するようにzshを設定するにはどうすればよいですか?
- リンクでリンクされたディレクトリに移動する