link simbólico para um diretório e caminho relativo

15

Eu criei o link simbólico com o caminho absoluto para o diretório (Blink) e, por exemplo, tenho a seguinte árvore:

$ 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

então eu vou para / tmp / A e mudo o diretório para Blink:

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

cd ..retorna para mim, /tmp/A mas se eu digitar, por exemplo ls ../foo, recebo erro:

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

O comando cd interno resolve o caminho conforme necessário, mas os ls externos consideram o .. como nível superior de / tmp / B e, portanto, não podem ser encontrados.

Qual é o problema aqui? Posso obter o arquivo foo de / tmp / A / Blink pelo caminho relativo como ../foo?

user478681
fonte
A mesma pergunta está cruzada no SuperUser
Peter.O

Respostas:

13

Eu não acho que você pode fazer isso. Atualmente, os shells controlam como chegaram onde estão, controlam o diretório de trabalho atual por nome, em vez de depender apenas do sistema de arquivos e do sistema operacional para mantê-lo. Isso significa que o built-in cdpode "fazer backup" do link simbólico, em vez de apenas seguir as cadeias ".." diretamente.

Mas quando você executa ls ../foo, lsnão está ciente de que o shell chegou a um diretório seguindo os links simbólicos. lsfará um stat()"../foo". A parte ".." vem do diretório atual, que possui apenas uma única entrada ".." para seu pai. A coisa toda do link simbólico não muda a maneira como os diretórios têm um único "." e uma única entrada "..". Links simbólicos permitem que o kernel insira uma camada extra de indireção nos caminhos dos arquivos. Quando você passa "../whatever" para open()ou stat(), o kernel apenas usa o diretório de trabalho atual do processo fazendo a chamada para descobrir qual diretório único é nomeado por "..".

Bruce Ediger
fonte
17

O shell armazena o diretório de trabalho atual em $PWD. Isso é o que é usado para as builtins shell cde pwd, e trata links simbólicos como diretórios normais, como você viu. Às vezes isso é útil, às vezes não.

Você pode encontrar o diretório real usando pwd(digite help pwdpara obter mais detalhes):

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

Da mesma forma, cdtem uma opção -P(novamente, help cdé seu amigo):

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

Por fim, você pode desativar o "recurso" completamente:

$ set -P
$ cd /tmp/A/Blink
$ pwd
/tmp/B
ams
fonte
Obrigado, eu estou ciente sobre o recurso conjunto -P, mas foi confundido por comando ls comportamento ...
user478681
Como eu disse, o uso set -Pe o comportamento começam a fazer sentido. :)
ams
2

Bruce e ams deram lindas respostas explicando o comportamento por trás. Mas para realmente fazer o que ls ../foovocê estava perguntando, você poderia usar algo como

ls $(dirname $PWD)/foo
Antti Vikman
fonte
1

Você não pode fazer isso, porque /tmp/A/Blink é realmente /tmp/B. Então, ls ../A/foofunciona.

Em vez disso, você pode achar útil poder fazer o cd no diretório real /tmp/B , em vez do alias /tmp/A/Blink. Para fazer isso, você pode usar a seguinte função em vez de cd(que você pode colocar no seu .bashrc)

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

lcd, é claro, funciona para os diretórios normais e vinculados simbólicos.
Nota: readlink -fatua no destino final do link (quando os links são encadeados).

Peter.O
fonte
1
cd -Pparece mais simples.
Jw013
@ jw013: Você está certo; isto é. Eu não estava ciente disso .. obrigado ..
Peter.O