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

15

Eu criei o symlink com o caminho absoluto para o diretório (Blink) e tenho, por exemplo, 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 .. me retorna para /tmp/A mas se eu digitar por exemplo ls ../foo eu vou ter erro:

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

comando embutido cd resolve caminho conforme necessário, mas ls externos consideram o .. como nível superior de / tmp / B e, portanto, não pode encontrar foo.

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

    
por user478681 12.04.2012 / 17:37

4 respostas

13

Eu não acho que você possa fazer isso. Shells hoje em dia controlam como eles chegaram onde estão, eles rastreiam o diretório de trabalho atual pelo nome, ao invés de confiar apenas no sistema de arquivos e SO para mantê-lo. Isso significa que o cd integrado pode "fazer backup" do link simbólico, em vez de apenas seguir ".." cadeias diretamente.

Mas quando você executa ls ../foo , ls não sabe que o shell chegou a um diretório seguindo os links simbólicos. ls fará um stat() em "../foo". A parte ".." vem do diretório atual, que tem apenas uma única entrada ".." para seu pai. Toda a coisa do link simbólico não altera 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 em caminhos de arquivo. 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 "..".

    
por 12.04.2012 / 18:07
17

O shell armazena o diretório de trabalho atual em $PWD . Isso é o que é usado para os integrantes do shell cd e pwd , e trata os 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 (type help pwd para mais detalhes):

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

Da mesma forma, cd tem 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":

$ set -P
$ cd /tmp/A/Blink
$ pwd
/tmp/B
    
por 12.04.2012 / 21:01
2

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

ls $(dirname $PWD)/foo
    
por 21.07.2012 / 08:05
1

Você não pode fazer isso porque /tmp/A/Blink é na verdade /tmp/B . Então, ls ../A/foo funciona.

Em vez disso, você pode achar útil 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 em seu .bashrc)

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

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

    
por 12.04.2012 / 20:18