Как сделать так, чтобы realpath никогда не разрешал символические ссылки?

Как сделать так, чтобы realpath никогда не разрешал символические ссылки?

Я ищу команду, которая вернет абсолютный путь к файлу, без разрешения символических ссылок. В общем, realpathделает это хорошо.

$ 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

Это также работает для файлов внутри каталогов символических ссылок.

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

Однако это не удается, когда нынешний директорявляетсякаталог символической ссылки

$ 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

Почему realpathтак происходит? (Это ошибка?) Есть ли способ realpathникогда не разрешать символическую ссылку или есть другой метод, который мне следует использовать?

решение1

Текущий рабочий каталог (CWD) процесса наследуется на уровне ОС от предыдущего процесса или может быть изменен для текущего процесса с помощью chdir(2). Операционная система (здесь я имею в виду «ядро»), конечно, всегда разрешит любую символическую ссылку, чтобы определить конечный результат, который должен быть каталогом, а не символической ссылкой (на каталог). Например, предыдущий системный вызов ( chdir(2)) может вернуть ошибку ELOOP, когда было слишком много символических ссылок для разрешения. Таким образом, с точки зрения ОС, не может быть CWD, не являющегося каталогом для какого-либо процесса: ОС всегда разрешит его как реальный путь без какой-либо символической ссылки где-либо.

После того, как оболочка выполнила cd /tmp/test/bar, путь CWD был разрешен ОС в /tmp/test/foo. Например, в системе Linux ls -l /proc/$$/cwdбудет показана ссылка на разрешенный путь, видимый ядром: /tmp/test/foo.

Тот факт, что оболочка все еще отображается barв приглашении, объясняется тем, что она помнитCDкоманда выполнена ранее. Поведение может зависеть от типа оболочки. Я предполагаю, что это bash. Так что это встроенная pwd(но не внешняя /bin/pwdкоманда), $PWDпеременная и ее использование $PS1будут «лгать» пользователю о текущем каталоге.

Любой процесс, например realpath, или /bin/pwdзапущенный из оболочки, конечно же унаследуетдействительныйCWD, который есть /tmp/test/foo. Так что это не ошибка в realpath, у него никогда не будет конкретной информации о bar.

Один из возможных неудобных способов, предложенный Кусаланандой, — это каким-то образом повторно использовать $PWDпеременную и добавлять ее к realpathаргументу только в том случае, если ее аргумент еще не является абсолютным.

Вот пример. Я не уверен, что нет способов злоупотребить этим. Например, хотя функция ниже справилась бы, $PWDсама переменная ведет себя не очень хорошо в bash 4.4.12 (Debian 9), но отлично работает в bash 5.0.3 (Debian 10), если в пути есть символ перевода строки. Когда где-то есть символ перевода строки, для того, чтобы быть полезным, -zтакже следует добавить опцию, realpathно я не собираюсь переписывать весь разбор опций в этом простом примере.

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

Связанный контент