
ディレクトリ (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
で使用され、これまで見てきたように、シンボリックリンクを通常のディレクトリとして扱います。これは役立つ場合もあれば、役に立たない場合もあります。cd
pwd
実際のディレクトリは、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 ../foo
、ls
シェルがシンボリック リンクをたどってディレクトリに到達したことを認識しません。 は、 "../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
リンクの最終ターゲットに作用します (リンクがデイジーチェーンされている場合)。