enlace simbólico a un directorio y ruta relativa

15

He creado un enlace simbólico con 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 ../foo, obtendré 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 por una ruta relativa como ../foo?

usuario478681
fuente
La misma pregunta se publica en SuperUser
Peter.O

Respuestas:

13

No creo que puedas hacer esto. Hoy en día, los shells realizan un seguimiento de cómo llegaron a donde están, hacen 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 la función incorporada cdpuede "respaldar" el enlace simbólico, en lugar de simplemente seguir las cadenas ".." directamente.

Pero cuando ejecuta ls ../foo, lsno es consciente de que el shell llegó a un directorio siguiendo enlaces simbólicos. lshará un stat()"../foo". La parte ".." proviene del directorio actual, que tiene una sola entrada ".." para su padre. Todo el enlace simbólico no cambia la forma en que los directorios tienen un solo "." y una sola entrada "..". Los enlaces simbólicos permiten que el núcleo inserte una capa adicional de indirección en las rutas de los archivos. Cuando se pasa "../whatever" a open()o stat(), el núcleo sólo utiliza el directorio de trabajo actual del proceso de hacer la llamada para averiguar qué solo directorio es nombrado por "..".

Bruce Ediger
fuente
17

El shell almacena el directorio de trabajo actual en $PWD. Eso es lo que se usa para las cáscaras incorporadas cdypwd , como has visto, trata los enlaces simbólicos como directorios normales. 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

Del mismo modo, cdtiene una opción -P(de nuevo, help cdes tu amigo):

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

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

$ set -P
$ cd /tmp/A/Blink
$ pwd
/tmp/B
ams
fuente
Gracias, soy consciente de la función set -P, pero estaba confundido por el comportamiento del comando ls ...
user478681
Como dije, el uso set -Py el comportamiento de ls comienzan a tener sentido. :)
enms.
2

Bruce y ams dieron hermosas respuestas explicando el comportamiento detrás. Pero para hacer realmente lo ls ../fooque estabas pidiendo, podrías ir con algo como

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

No puedes hacerlo, porque /tmp/A/Blink es en realidad /tmp/B. Entonces,ls ../A/foo funciona.

En su lugar, puede resultarle útil poder cd al directorio real /tmp/B , en lugar del alias /tmp/A/Blink. Para hacer eso, puede usar la siguiente función en lugar de cd(que puede poner en su .bashrc)

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

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

Peter.O
fuente
1
cd -Pparece más simple
jw013
@ jw013: Tienes razón; está. Yo no era consciente de ello .. gracias ..
Peter.O