web-dev-qa-db-ja.com

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

私はディレクトリへの絶対パス(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を見つけることができません。

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

15
user478681

あなたはこれを行うことができないと思います。シェルは現在、ファイルシステムとOSに依存するだけでなく、現在の作業ディレクトリを名前で追跡するのではなく、現在の作業ディレクトリを追跡しています。つまり、組み込みのcdは、「..」チェーンを直接たどるのではなく、シンボリックリンクを「バックアップ」できるということです。

ただし、_ls ../foo_を実行すると、lsは、シェルがシンボリックリンクをたどってディレクトリに到達したことを認識しません。 lsは "../foo"に対してstat()を実行します。 「..」の部分は現在のディレクトリからのもので、現在のディレクトリには親の「..」エントリが1つだけあります。全体のシンボリックリンクは、ディレクトリに単一の「。」がある方法を変更しません。および単一の「..」エントリ。シンボリックリンクを使用すると、カーネルは間接的な層をファイルパスに追加できます。 「../whatever」をopen()またはstat()に渡すと、カーネルは、呼び出しを実行しているプロセスの現在の作業ディレクトリを使用して、「 ……」.

13
Bruce Ediger

シェルは現在の作業ディレクトリを$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
17
ams

ブルースとアムスは背後にある行動を説明する美しい答えを出しました。しかし実際にls ../fooあなたが求めていた、あなたは次のようなもので行くことができます

ls $(dirname $PWD)/foo
2
Antti Vikman

/tmp/A/Blinkisは実際には/tmp/Bであるため、それを行うことはできません。したがって、ls ../A/fooは機能します。

cdrealに変換できると便利な場合がありますエイリアスされた/tmp/Bではなく、/tmp/A/Blinkディレクトリ。これを行うには、cdの代わりに次の関数を使用できます(.bashrcに入れることができます)

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

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

1
Peter.O