¿Cómo puedo hacer que realpath nunca resuelva enlaces simbólicos?

¿Cómo puedo hacer que realpath nunca resuelva enlaces simbólicos?

Estoy buscando un comando para devolver la ruta absoluta de un archivo, sin resolver enlaces simbólicos. En general, realpathlo hace bien.

$ mkdir /tmp/test; cd /tmp/test
$ mkdir foo
$ ln -s foo bar
$ realpath -se bar           # good, this does not resolve the symlink
/tmp/test/bar

También funciona para archivos dentro de directorios de enlaces simbólicos.

$ touch foo/file
$ realpath -se bar/file      # good, this does not resolve the symlink
/tmp/test/bar/file

Sin embargo, fracasa cuando el actual directoresun directorio de enlace simbólico

$ cd bar
$ pwd
/tmp/test/bar
$ realpath -se file          # this fails, returning the target
/tmp/test/foo/file
$ realpath -se .             # this also fails, returning the target
/tmp/test/foo
$ realpath -se /tmp/test/bar/file # yet this works
/tmp/test/bar/file
$ realpath -se /tmp/test/bar # and this works
/tmp/test/bar

¿Por qué se realpathcomportaría así? (¿Es un error?) ¿Hay alguna manera de evitar realpathque nunca se resuelva el enlace simbólico, o hay otro método que debería usar?

Respuesta1

El directorio de trabajo actual (CWD) de un proceso se hereda en el nivel del sistema operativo del proceso anterior o se puede cambiar para el proceso actual usando chdir(2). El sistema operativo (aquí me refiero a "el núcleo"), por supuesto, siempre resolverá cualquier enlace simbólico para determinar el resultado final, que debe ser un directorio, no un enlace simbólico (a un directorio). Por ejemplo, la llamada al sistema anterior ( chdir(2)) puede devolver el error ELOOPcuando había demasiados enlaces simbólicos para resolver. Entonces, desde el punto de vista del sistema operativo, no puede haber un CWD que no sea un directorio para ningún proceso: el sistema operativo siempre lo resolverá en la ruta real sin ningún enlace simbólico en ninguna parte.

Una vez que el shell lo hizo cd /tmp/test/bar, el sistema operativo resolvió la ruta CWD en /tmp/test/foo. Por ejemplo, en un sistema Linux, ls -l /proc/$$/cwdse mostrará el enlace a la ruta resuelta tal como la ve el kernel: /tmp/test/foo.

El hecho de que el shell todavía se muestre baren su mensaje es que debido a que recuerda elcdcomando hecho antes. El comportamiento podría depender del tipo de caparazón. Asumiré bash aquí. Por lo tanto, está integrado (pero no el comando pwdexterno ), la variable y su uso "mentirán" al usuario sobre el directorio actual./bin/pwd$PWD$PS1

Cualquier proceso, como realpath, o /bin/pwdejecutado desde el shell, por supuesto, heredará elactualCWD, que es /tmp/test/foo. Así que eso no es un error realpath, nunca tendrá información específica sobre él bar.

Una posible forma incómoda, como sugiere Kusalananda, es reutilizar de alguna manera la $PWDvariable y anteponerla al realpathargumento solo si su argumento aún no es absoluto.

He aquí un ejemplo. No estoy seguro de que no haya formas de abusar de él. Por ejemplo, si bien la siguiente función funciona, la $PWDvariable en sí no se comporta bien en bash 4.4.12 (Debian 9), pero funciona bien en bash 5.0.3 (Debian 10) si hay un carácter de salto de línea en la ruta. Cuando hay un salto de línea en alguna parte, para que sea útil, -ztambién se debe agregar una opción, realpathpero no voy a volver a implementar todo el análisis de opciones en este ejemplo simple.

myrealpathnofollowsym () {
    for p in "$@"; do
        if ! printf '%s' "$p" | grep -q -- '^/'; then
            realpath -se "$PWD/$p"
        else
            realpath -se "$p"
        fi
    done
}

información relacionada