Как я могу получить поведение readlink GNU-f на Mac?

До 1 января 1970 года истина и ложь были наоборот ...

341
задан SamB 11 February 2012 в 09:04
поделиться

5 ответов

readlink -f делает две вещи:

  1. Он выполняет итерацию по последовательности символических ссылок, пока не найдет реальный файл.
  2. Он возвращает канонизированное имя этого файла, то есть его абсолютный путь.

Если вы хотите, вы можете просто построить сценарий оболочки, который использует обычное поведение readlink для достижения того же результата. Вот вам пример. Очевидно, вы можете вставить это в свой собственный скрипт, где вы хотите вызвать readlink -f

#!/bin/sh

TARGET_FILE=$1

cd `dirname $TARGET_FILE`
TARGET_FILE=`basename $TARGET_FILE`

# Iterate down a (possible) chain of symlinks
while [ -L "$TARGET_FILE" ]
do
    TARGET_FILE=`readlink $TARGET_FILE`
    cd `dirname $TARGET_FILE`
    TARGET_FILE=`basename $TARGET_FILE`
done

# Compute the canonicalized name by finding the physical path 
# for the directory we're in and appending the target file.
PHYS_DIR=`pwd -P`
RESULT=$PHYS_DIR/$TARGET_FILE
echo $RESULT

Обратите внимание, что это не включает никакой обработки ошибок. Что особенно важно, он не определяет циклы символических ссылок. Простой способ сделать это - подсчитать, сколько раз вы обходите цикл и терпят неудачу, если вы набираете невероятно большое число, например 1000.

164
ответ дан 23 November 2019 в 00:35
поделиться

Пути к ссылке для чтения в моей и вашей системе различаются. Пожалуйста, попробуйте указать полный путь:

/ sw / sbin / readlink -f

-4
ответ дан 23 November 2019 в 00:35
поделиться

Возможно, вас заинтересует realpath (3) или Python os.path.realpath . Это не совсем то же самое; вызов библиотеки C требует наличия компонентов промежуточного пути, в то время как версия Python не существует.

$ pwd
/tmp/foo
$ ls -l
total 16
-rw-r--r--  1 miles    wheel  0 Jul 11 21:08 a
lrwxr-xr-x  1 miles    wheel  1 Jul 11 20:49 b -> a
lrwxr-xr-x  1 miles    wheel  1 Jul 11 20:49 c -> b
$ python -c 'import os,sys;print(os.path.realpath(sys.argv[1]))' c
/private/tmp/foo/a

Я знаю, что вы сказали, что предпочитаете что-то более легкое, чем другой язык сценариев, но на всякий случай, если компиляция двоичного файла невыносима, вы можете использовать Python и ctypes (доступны в Mac OS X 10.5), чтобы обернуть вызов библиотеки:

#!/usr/bin/python

import ctypes, sys

libc = ctypes.CDLL('libc.dylib')
libc.realpath.restype = ctypes.c_char_p
libc.__error.restype = ctypes.POINTER(ctypes.c_int)
libc.strerror.restype = ctypes.c_char_p

def realpath(path):
    buffer = ctypes.create_string_buffer(1024) # PATH_MAX
    if libc.realpath(path, buffer):
        return buffer.value
    else:
        errno = libc.__error().contents.value
        raise OSError(errno, "%s: %s" % (libc.strerror(errno), buffer.value))

if __name__ == '__main__':
    print realpath(sys.argv[1])

Как ни странно, версия C этого сценария должна быть короче. :)

43
ответ дан 23 November 2019 в 00:35
поделиться

Я лично создал сценарий под названием realpath, который выглядит примерно так:

#!/usr/bin/env python
import os.sys
print os.path.realpath(sys.argv[1])
18
ответ дан 23 November 2019 в 00:35
поделиться

Вот переносимая функция оболочки, которая должна работать в ЛЮБОЙ оболочке, сопоставимой с Борном. Она разрешит относительный путь пунктуация ".. или." и разыменование символических ссылок.

Если по какой-то причине у вас нет команды realpath (1) или readlink (1), это может быть псевдонимом.

which realpath || alias realpath='real_path'

Наслаждайтесь:

real_path () {
  OIFS=$IFS
  IFS='/'
  for I in $1
  do
    # Resolve relative path punctuation.
    if [ "$I" = "." ] || [ -z "$I" ]
      then continue
    elif [ "$I" = ".." ]
      then FOO="${FOO%%/${FOO##*/}}"
           continue
      else FOO="${FOO}/${I}"
    fi

    ## Resolve symbolic links
    if [ -h "$FOO" ]
    then
    IFS=$OIFS
    set `ls -l "$FOO"`
    while shift ;
    do
      if [ "$1" = "->" ]
        then FOO=$2
             shift $#
             break
      fi
    done
    IFS='/'
    fi
  done
  IFS=$OIFS
  echo "$FOO"
}

также на всякий случай, если кого-то интересует, как реализовать базовое имя и имя каталога в 100% чистом коде оболочки:

## http://www.opengroup.org/onlinepubs/000095399/functions/dirname.html
# the dir name excludes the least portion behind the last slash.
dir_name () {
  echo "${1%/*}"
}

## http://www.opengroup.org/onlinepubs/000095399/functions/basename.html
# the base name excludes the greatest portion in front of the last slash.
base_name () {
  echo "${1##*/}"
}

Вы можете найти обновленную версию этого кода оболочки на моем сайте в Google: http://sites.google.com/site/jdisnard/realpath

РЕДАКТИРОВАТЬ: Этот код лицензирован в соответствии с условиями лицензии с двумя пунктами (стиль FreeBSD). A копию лицензии можно найти, перейдя по указанной выше гиперссылке на мой сайт.

7
ответ дан 23 November 2019 в 00:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: