enlace simbólico a un directorio y ruta relativa

enlace simbólico a un directorio y ruta relativa

Creé un enlace simbólico con una ruta absoluta al directorio (Blink) y tengo, por ejemplo, el siguiente árbol:

$ 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

luego voy a /tmp/A y cambio el directorio a Blink:

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

cd ..me devuelve a /tmp/A pero si escribo, por ejemplo, ls ../fooobtendré un error:

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

El comando cd incorporado resuelve la ruta según sea necesario, pero los ls externos consideran el .. como nivel superior de /tmp/B y, por lo tanto, no pueden encontrar foo.

¿Cuál es el problema aquí? ¿Puedo obtener el archivo foo de /tmp/A/Blink mediante una ruta relativa como ../foo?

Respuesta1

El shell almacena el directorio de trabajo actual en formato $PWD. Eso es lo que se usa para las funciones integradas del shell cdy pwd, y trata los enlaces simbólicos como directorios normales, como has visto. A veces esto es útil, a veces no.

Puede encontrar el directorio real usando pwd(escriba help pwdpara obtener más detalles):

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

Asimismo, cdtiene una opción -P(nuevamente, help cdes tu amiga):

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

Finalmente, puedes desactivar la "función" por completo:

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

Respuesta2

No creo que puedas hacer esto. Hoy en día, los shells realizan un seguimiento de cómo llegaron a donde están, realizan un seguimiento del directorio de trabajo actual por nombre, en lugar de depender únicamente del sistema de archivos y el sistema operativo para mantenerlo. Eso significa que el integrado cdpuede hacer una "copia de seguridad" del enlace simbólico, en lugar de simplemente seguir las cadenas ".." directamente.

Pero cuando ejecuta ls ../foo, lsno se da cuenta de que el shell llegó a un directorio siguiendo enlaces simbólicos. lshará un stat()en "../foo". La parte ".." proviene del directorio actual, que tiene una sola entrada ".." para su padre. Todo el asunto del enlace simbólico no cambia la forma en que los directorios tienen un solo "." y una única entrada ".." Los enlaces simbólicos permiten que el kernel inserte una capa adicional de direccionamiento indirecto en las rutas de los archivos. Cuando pasa "../lo que sea" a open()o stat(), el kernel simplemente usa el directorio de trabajo actual del proceso que realiza la llamada para determinar qué directorio único se nombra con "..".

Respuesta3

Bruce y ams dieron hermosas respuestas explicando el comportamiento detrás. Pero para hacer realmente lo ls ../fooque pedías, podrías optar por algo como

ls $(dirname $PWD)/foo

Respuesta4

No puedes hacerlo, porque/tmp/A/Blink esde hecho /tmp/B. Entonces, ls ../A/foofunciona.

En su lugar, puede que le resulte útil podercdhaciareal /tmp/Bdirectorio, en lugar del alias /tmp/A/Blink. Para hacer eso, puedes usar la siguiente función en lugar de cd(que puedes poner en tu .bashrc)

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

lcd, por supuesto, funciona tanto para directorios normales como para directorios vinculados simbólicamente.
Nota: readlink -factúa sobre el destino final del enlace (cuando los enlaces están encadenados).

información relacionada