ディレクトリと相対パスへのシンボリックリンク

ディレクトリと相対パスへのシンボリックリンク

ディレクトリ (Blink) への絶対パスでシンボリックリンクを作成し、たとえば次のツリーを作成しました。

$ ls -l /tmp/A
total 0
lrwxrwxrwx 1 root root 6 Apr  3 12:27 Blink -> /tmp/B
-rw-r--r-- 1 root root 0 Apr  3 12:27 foo

$ ls -l /tmp/B
total 0
-rw-r--r-- 1 root root 0 Apr  3 12:27 bar

次に、/tmp/A に移動して、ディレクトリを Blink に変更します。

$ cd /tmp/A
$ pwd
/tmp/A
$ cd Blink
$ pwd
/tmp/A/Blink

cd ..に戻ります/tmp/A が、たとえば次のように入力するとls ../fooエラーが発生します。

ls: ../foo: No such file or directory

組み込みの cd コマンドは必要に応じてパスを解決しますが、外部の ls は .. を /tmp/B の上位レベルと見なすため、foo を見つけることができません。

ここで何が問題なのでしょうか? ../foo のような相対パスで /tmp/A/Blink から foo ファイルを取得できますか?

答え1

シェルは現在の作業ディレクトリを に保存します。これはシェルの組み込みコマンドおよび$PWDで使用され、これまで見てきたように、シンボリックリンクを通常のディレクトリとして扱います。これは役立つ場合もあれば、役に立たない場合もあります。cdpwd

実際のディレクトリは、pwd(help pwd詳細を表示するには入力してください) を使用して見つけることができます:

$ pwd
/tmp/A/Blink
$ pwd -L
/tmp/A/Blink
$ pwd -P
/tmp/B

同様に、cdオプションがあります-P(これもhelp cdあなたの友達です):

$ cd /tmp/A/Blink
$ pwd
/tmp/A/Blink
$ cd -P ..
$ pwd -P
/tmp

最後に、「機能」を完全にオフにすることもできます。

$ set -P
$ cd /tmp/A/Blink
$ pwd
/tmp/B

答え2

これはできないと思います。最近のシェルは、ファイル システムや OS に頼るのではなく、現在の作業ディレクトリを名前で追跡し、現在の場所にどのようにたどり着いたかを追跡します。つまり、組み込み関数はcd、単に「..」チェーンを直接たどるのではなく、シンボリック リンクを「バックアップ」できるということです。

しかし、 を実行すると、 はls ../foolsシェルがシンボリック リンクをたどってディレクトリに到達したことを認識しません。 は、 "../foo" に対してlsを実行しますstat()。 ".." の部分は、現在のディレクトリから取得されます。現在のディレクトリには、その親の ".." エントリが 1 つしかありません。シンボリック リンク全体によって、ディレクトリが 1 つの "." と 1 つの ".." エントリを持つ方法が変わることはありません。シンボリック リンクにより、カーネルはファイル パスに間接的なレイヤーを追加できます。 または に "../whatever" を渡すとopen()stat()カーネルは呼び出しを実行するプロセスの現在の作業ディレクトリを使用して、どのディレクトリが ".." で名前付けされているかを判断します。

答え3

ブルースとアムスは、背後にある行動を説明する素晴らしい答えを出しました。しかし、ls ../fooあなたが尋ねていたことを実際に実行するには、次のような方法があります。

ls $(dirname $PWD)/foo

答え4

それはできない、なぜなら/tmp/A/Blink 実際に/tmp/B。つまり、ls ../A/foo機能します。

代わりに、次のことができると便利かもしれませんCD本物 /tmp/Bディレクトリではなく、エイリアス化された を/tmp/A/Blink使用します。これを行うには、 の代わりに次の関数を使用しますcd(.bashrc に配置できます)。

lcd() { cd $(readlink -f "$1"); }

lcdもちろん、通常のディレクトリとシンボリックリンクされたディレクトリの両方で機能します。
注:readlink -fリンクの最終ターゲットに作用します (リンクがデイジーチェーンされている場合)。

関連情報