MacでGNUのreadlink -fの動作を取得するにはどうすればよいですか?


377

Linuxでは、readlinkユーティリティは-f追加のリンクをたどるオプションを受け入れます。これはMacやBSDベースのシステムでは機能しないようです。同等のものは何でしょうか?

デバッグ情報は次のとおりです。

$ which readlink; readlink -f
/usr/bin/readlink
readlink: illegal option -f
usage: readlink [-n] [file ...]

1
少し遅れますが、使用しているシェルについての言及が不足しています。readlink組み込みコマンドまたは外部コマンドになる可能性があるため、これは重要です。
0xC0000022L

1
それはおそらく違いを説明するでしょう。私はどちらの場合でもbashを使用したと確信しています。
troelskn

1
このオプションがMacでは違法なのはなぜですか?
CommaToast 2014

3
AppleがOS Xでより多くのデフォルトのlinuxパスをサポートし、このような問題に対処してくれることを本当に望みます。彼らは何も壊すことなくそれを行うことができましたね?
CommaToast 2014

1
@CommaToastまあ、それらはPerlに同梱されているので++ :-) ... Terminal.appを開いtouch myfile ; ln -s myfile otherfile ; perl -MCwd=abs_path -le 'print abs_path readlink(shift);' otherfileて次のように入力します。以下の私の応答に追加しました。乾杯。
G. Cito 2015

回答:


181

readlink -f 次の2つのことを行います。

  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

これにはエラー処理が含まれていないことに注意してください。特に重要なのは、シンボリックリンクのサイクルを検出しないことです。これを行う簡単な方法は、ループを回避する回数を数え、1,000などの非常に大きな数に達した場合に失敗することです。

pwd -P代わりに使用するように編集されました$PWD

このスクリプトを期待は次のように呼び出されることに注意してください./script_name filename、ない-f、変更$1$2あなたが使用できるようにしたい場合は-f filenameGNUのREADLINKのように。


1
私の知る限り、パスの親ディレクトリがシンボリックリンクの場合は機能しません。例えば。の場合foo -> /var/cux、リンクではありませfoo/barんが解決されbarませんfoo
troelskn 2009

1
ああ。はい。それほど単純ではありませんが、上記のスクリプトを更新してこれに対処できます。私はそれに応じて答えを編集します(本当に書き換えます)。
キーススミス

まあ、リンクはパスのどこにあってもかまいません。スクリプトはパスの各部分を繰り返すことができると思いますが、その場合は少し複雑になります。
troelskn 2009

1
ありがとう。問題は、$ PWDが、追跡したシンボリックリンクの値に基づいて、論理作業ディレクトリを提供していることです。「pwd -P」を使用して実際の物理ディレクトリを取得できます。ファイルシステムのルートまで「..」を追跡することで、ディレクトリを計算する必要があります。それに応じて、回答のスクリプトを更新します。
キース・スミス

12
すばらしい解決策ですが、スペース埋め込まれたファイル名やディレクトリ名など、エスケープが必要なパスは適切に処理されません。それを修正するには、上記のコードの適切な場所でand を使用 します。cd "$(dirname "$TARGET_FILE")"TARGET_FILE=$(readlink "$TARGET_FILE")TARGET_FILE=$(basename "$TARGET_FILE")
mklement0 2012

438

MacPortsとHomebrewは、(GNU readlink)を含むcoreutilsパッケージを提供しますgreadlink。mackb.comのMichael Kallweittの投稿のクレジット。

brew install coreutils

greadlink -f file.txt

bash以外の場所からreadlinkを呼び出す場合、別の解決策として、/ usr / bin / readlinkを削除してから、/ usr / local / bin / greadlinkへのリンクを作成します。
chinglun 2014年

8
a)自分用のソフトウェアを作成するb)他のユーザーを混乱させたくない場合を除いて、しないでください。だれでも「うまくいく」ように書いてください。
kgadek

14
@ching代わりに次のようにしてください.bashrcexport PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"
bfontaine '25

1
質問はOS XまたはBSDシステムで同等のものを求めますが、これは答えません。Homebrewもインストールする必要があります。また、GNU Readlink以外にも多くのものをインストールします。標準のOS Xインストール用のスクリプトを作成している場合、この回答は役に立ちません。OS Xでは、何もインストールせずにpwd -Pとの組み合わせを使用できますreadlink
Jason S

4
私は、プレフィックスなしで、ユーザーのから簡単にアクセスできると確信している、私のMac上のGNUおよびその他のユーティリティを望んでいましPATH。上記はで始まりましたbrew install <package> --default-names。このサイトの質問の多くは、質問者の技術的要件の範囲外であるが、同様の状況の範囲内でわずかに、またはそれ以上に回答されており、依然として非常に役に立ちました。 topbug.ne​​t/blog/2013/04/14/...
Pysis

43

あなたはrealpath(3)、またはPythonのに興味があるかもしれませんos.path.realpath。2つはまったく同じではありません。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バージョンは短くする必要があります。:)


はい、realpath確かに私が欲しいものです。しかし、この関数をシェルスクリプトから取得するためにバイナリをコンパイルしなければならないのはかなり厄介なようです。
troelskn 2009

4
では、シェルスクリプトでPythonワンライナーを使用してみませんか?(readlinkそれ自体への1行の呼び出しとそれほど違いはありませんか?)
Telemachus

3
python -c "import os,sys; print(os.path.realpath(os.path.expanduser(sys.argv[1])))" "${1}"次のようなパスで機能します'~/.symlink'
Wes Turner

@troelskin Perl、Python などが「許可」されていることに気づかなかった!! ...その場合、私はperl -MCwd=abs_path -le 'print abs_path readlink(shift);'私の答えに追加します:-)
G. Cito 2015

27

私はさらに別の実装を重ねるのが嫌いですが、このようなもののエッジケースの数は重要でないので、a)移植可能な純粋なシェル実装、およびb)ユニットテストカバレッジが必要でした。

テストと完全なコードについては、Github私のプロジェクトを参照しください。次に、実装の概要を示します。

キース・スミスが鋭敏に指摘するように、readlink -f2つのことを行います。1)シンボリックリンクを再帰的に解決し、2)結果を正規化します。

realpath() {
    canonicalize_path "$(resolve_symlinks "$1")"
}

最初に、symlinkリゾルバーの実装:

resolve_symlinks() {
    local dir_context path
    path=$(readlink -- "$1")
    if [ $? -eq 0 ]; then
        dir_context=$(dirname -- "$1")
        resolve_symlinks "$(_prepend_path_if_relative "$dir_context" "$path")"
    else
        printf '%s\n' "$1"
    fi
}

_prepend_path_if_relative() {
    case "$2" in
        /* ) printf '%s\n' "$2" ;;
         * ) printf '%s\n' "$1/$2" ;;
    esac 
}

これは完全実装のわずかに簡略化されたバージョンであることに注意してください。完全な実装は、シンボリックリンクの小さなチェックを追加し、出力を少しマッサージします。

最後に、パスを正規化する関数:

canonicalize_path() {
    if [ -d "$1" ]; then
        _canonicalize_dir_path "$1"
    else
        _canonicalize_file_path "$1"
    fi
}   

_canonicalize_dir_path() {
    (cd "$1" 2>/dev/null && pwd -P) 
}           

_canonicalize_file_path() {
    local dir file
    dir=$(dirname -- "$1")
    file=$(basename -- "$1")
    (cd "$dir" 2>/dev/null && printf '%s/%s\n' "$(pwd -P)" "$file")
}

それで、多かれ少なかれそれです。スクリプトに貼り付けるのに十分なほど単純ですが、ユースケース用の単体テストを持たないコードに依存するのに夢中になるほどトリッキーです。


3
これはPOSIXではありません-非POSIX localキーワードを使用しています
go2null

これはreadlink -f、またはと同等ではありませんrealpath。coreutils数式がインストールされているMacを想定しているため(greadlink利用可能であるため)、これをで試してくださいln -s /tmp/linkeddir ~/Documentsgreadlink -f /tmp/linkeddir/..ホームディレクトリには、印刷し(それが解決/tmp/linkeddir適用する前にリンクを..親ディレクトリの参照を)が、あなたのコードが生成/private/tmp/として/tmp/linkeddir/..シンボリックリンクではありませんが、-d /tmp/linkeddir/..本当ですのでcd /tmp/linkeddir/..が表示されます/tmp、その正規のパスです/private/tmprealpath -L代わりに、あなたのコードが何をするかを行います。
Martijn Pieters

27

外部の依存関係がなくてもほぼすべての場所で動作することが確実なperlのシンプルなワンライナー:

perl -MCwd -e 'print Cwd::abs_path shift' ~/non-absolute/file

シンボリックリンクを逆参照します。

スクリプトでの使用法は次のようになります。

readlinkf(){ perl -MCwd -e 'print Cwd::abs_path shift' "$1";}
ABSPATH="$(readlinkf ./non-absolute/file)"

4
末尾の改行を取得するには-l、次のように追加しますperl -MCwd -le 'print Cwd::abs_path shift' ~/non-absolute/file
pjvandehaar 2018年

26
  1. 自作をインストールする
  2. 「brew install coreutils」を実行します
  3. 「greadlink -f path」を実行します

greadlinkは、-fを実装するgnu readlinkです。Macportsなども使用できますが、自作のほうが好きです。



これらのコマンドを通常の名前で使用する必要がある場合は、次のようにbashrcからPATHに「gnubin」ディレクトリを追加できます。PATH= "/ usr / local / opt / coreutils / libexec / gnubin:$ PATH"
Denis

20

私はrealpathと呼ばれるスクリプトを個人的に作成しました。

#!/usr/bin/env python
import os.sys
print os.path.realpath(sys.argv[1])

sys.argv[1]スクリプトで最初の引数の実際のパスを出力する場合は、これをに変更する必要があります。sys.argv[0]pytonスクリプト自体の実際のパスを出力するだけなので、あまり役に立ちません。
Jakob Egger

17
ここでのエイリアスのバージョンは、です~/.profilealias realpath="python -c 'import os, sys; print os.path.realpath(sys.argv[1])'"
jwhitlock

すばらしい答え、そしてすばらしい1行@jwhitlock。OPが引用されているのでreadlink -f、ここでは@jwhitlockの修正版の可能性をサポートするためのエイリアスです-f:フラグ alias realpath="python -c 'import os, sys; print os.path.realpath(sys.argv[2] if sys.argv[1] == \"-f\" else sys.argv[1])'"
codesniffer

11

これはどうですか?

function readlink() {
  DIR="${1%/*}"
  (cd "$DIR" && echo "$(pwd -P)")
}

これが私にとって有効な唯一の解決策です。../../../->/
keflavich

/usr/bin/たとえば、alternativesシステムが好むようなシンボリックリンクがある場合、これは機能しません。
akostadinov 2013

個々のファイルでは機能せず、ディレクトリでのみ機能します。GNU readlinkは、ディレクトリ、ファイル、シンボリックリンクなどで動作します
codesiffer

7

以下は、あらゆる Bourne 互換シェルで機能するポータブルシェル関数です。相対パスの句読点「..または。」を解決します。シンボリックリンクを逆参照します。

なんらかの理由で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%純粋なシェルコードでbasenameとdirnameを実装する方法があります:

## 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)にあります。

編集:このコードは、2句(freeBSDスタイル)ライセンスの条件に基づいてライセンスされます。私のサイトへの上記のハイパーリンクをたどることにより、ライセンスのコピーを見つけることができます。


real_pathは、bashシェルのMac OS X Lionで/ path / to / filenameではなく/ filenameを返します。

@Barry OSX Snow Leopardでも同じことが起こります。さらに悪いことに、real_path()を連続して呼び出すと、出力が連結されます。
ドミニク

@Dominique:関数の内部は独自のサブシェルで実行されないため、当然のことですが、醜くて壊れやすいものです。
0xC0000022L

7

FreeBSDOSXには、statNetBSDから派生したバージョンがあります。

出力はフォーマットスイッチで調整できます(上記のリンクにあるマニュアルページを参照してください)。

%  cd  /service
%  ls -tal 
drwxr-xr-x 22 root wheel 27 Aug 25 10:41 ..
drwx------  3 root wheel  8 Jun 30 13:59 .s6-svscan
drwxr-xr-x  3 root wheel  5 Jun 30 13:34 .
lrwxr-xr-x  1 root wheel 30 Dec 13 2013 clockspeed-adjust -> /var/service/clockspeed-adjust
lrwxr-xr-x  1 root wheel 29 Dec 13 2013 clockspeed-speed -> /var/service/clockspeed-speed
% stat -f%R  clockspeed-adjust
/var/service/clockspeed-adjust
% stat -f%Y  clockspeed-adjust
/var/service/clockspeed-adjust

の一部のOS Xバージョンにstat-f%R、フォーマットのオプションがない場合があります。この場合-stat -f%Yは十分かもしれません。-f%Yオプションが、一方、シンボリックリンクのターゲットが表示されます-f%R示す絶対パス名は、ファイルに対応します。

編集:

Perlを使用できる場合(Darwin / OS Xには、最新バージョンのがインストールされていますperl):

perl -MCwd=abs_path -le 'print abs_path readlink(shift);' linkedfile.txt

働くでしょう。


2
これはFreeBSD 10には当てはまりますが、OS X 10.9には当てはまりません。
Zanchey 2014年

良いキャッチ。マニュアルページはSTAT引用は、OS / X 10.9用です。へのRオプションが-f%ありません。stat -f%Y必要な出力が得られる可能性があります。答えを調整します。このstatツールはバージョン4.10のFreeBSDとバージョン1.6のNetBSDで登場したことに注意してください。
G. Cito 2014年

Perlコマンドは10.15では正しく機能しません。現在のディレクトリにファイルを渡し、現在のディレクトリ(ファイルなし)を与えます。
コードスニファー

7

この問題を解決し、HomebrewがインストールされたMacまたはFreeBSDでreadlinkの機能を有効にする最も簡単な方法は、「c​​oreutils」パッケージをインストールすることです。特定のLinuxディストリビューションやその他のPOSIX OSでも必要になる場合があります。

たとえば、FreeBSD 11では、次のコマンドを実行してインストールしました。

# pkg install coreutils

Homebrewを搭載したMacOSでは、コマンドは次のようになります。

$ brew install coreutils

他の答えがなぜそれほど複雑であるのか本当にわからない、それだけです。ファイルは別の場所にありません。まだインストールされていません。


7
brew install coreutils --with-default-names具体的には。または、代わりに「greadlink」で終わることになります...
Henk

2010 stackoverflow.com/a/4031502/695671と2012 stackoverflow.com/a/9918368/695671からの回答に違いはありません。質問は、実際には「... MacおよびおそらくBSDベースのシステムです。同等ですか?」これはその質問に対する非常に良い答えだとは思いません。多くの理由がありますが、何もインストールできないMac OSマシンをターゲットにしている可能性があります。pwd -P非常に単純ですが、繰り返しの回答を含む他の多くの回答の中で消えてしまうため、反対票が出ます。
ジェイソンS

3

更新を開始

これは頻繁に発生する問題であり、realpath-libと呼ばれる無料で使用できるBash 4ライブラリ(MITライセンス)をまとめました。これは、デフォルトでreadlink -fをエミュレートするように設計されており、(1)特定のUNIXシステムで動作すること、および(2)インストールされている場合はreadlink -fに対して検証する2つのテストスイートを含みます(ただし、これは必須ではありません)。さらに、深い、壊れたシンボリックリンクと循環参照を調査、識別、およびアンワインドするために使用できるため、深くネストされた物理ディレクトリまたはシンボリックディレクトリとファイルの問題を診断するための有用なツールとなります。それはで見つけることができgithub.comまたはbitbucket.org

更新を終了

Bash以外に依存しない、もう1つの非常にコンパクトで効率的なソリューションは次のとおりです。

function get_realpath() {

    [[ ! -f "$1" ]] && return 1 # failure : file does not exist.
    [[ -n "$no_symlinks" ]] && local pwdp='pwd -P' || local pwdp='pwd' # do symlinks.
    echo "$( cd "$( echo "${1%/*}" )" 2>/dev/null; $pwdp )"/"${1##*/}" # echo result.
    return 0 # success

}

これにはno_symlinks、物理システムへのシンボリックリンクを解決する機能を提供する環境設定も含まれます。no_symlinks何かに設定されている限り、つまりno_symlinks='on'シンボリックリンクは物理システムに解決されます。それ以外の場合は適用されます(デフォルト設定)。

これは、Bashを提供するすべてのシステムで機能し、テスト目的でBash互換の終了コードを返します。


3

すでに多くの回答がありますが、どれもうまくいきませんでした...これが私が現在使用しているものです。

readlink_f() {
  local target="$1"
  [ -f "$target" ] || return 1 #no nofile

  while [ -L "$target" ]; do
    target="$(readlink "$target")" 
  done
  echo "$(cd "$(dirname "$target")"; pwd -P)/$target"
}

1
これが$targetパスの場合は機能せず、ファイルの場合にのみ機能します。
MaxGhost 2017年

3

私のために働く怠惰な方法、

$ brew install coreutils
$ ln -s /usr/local/bin/greadlink /usr/local/bin/readlink
$ which readlink
/usr/local/bin/readlink
/usr/bin/readlink

1

遅くなったほうがましだと思います。私のFedoraスクリプトがMacで動作していなかったので、私は特にこれを開発する動機がありました。問題は依存関係とBashです。Macにはそれらがありません。または、ある場合、別の場所にあることがよくあります(別のパス)。クロスプラットフォームのBashスクリプトでの依存関係パスの操作は、せいぜい頭痛の種であり、最悪の場合はセキュリティリスクです。そのため、可能であればそれらの使用を避けるのが最善です。

以下のget_realpath()関数はシンプルでBash中心であり、依存関係は必要ありません。私はBashビルトインのechocdのみを使用しています。すべてが方法の各段階でテストされ、エラー状態が返されるため、これもかなり安全です。

シンボリックリンクを追跡したくない場合は、スクリプトの前にset -Pを配置しますが、それ以外の場合、cdはデフォルトでシンボリックリンクを解決します。これは、{absolute | 親族| シンボリックリンク| そして、ファイルへの絶対パスを返します。これまでのところ問題はありません。

function get_realpath() {

if [[ -f "$1" ]]
then
    # file *must* exist
    if cd "$(echo "${1%/*}")" &>/dev/null
    then
        # file *may* not be local
        # exception is ./file.ext
        # try 'cd .; cd -;' *works!*
        local tmppwd="$PWD"
        cd - &>/dev/null
    else
        # file *must* be local
        local tmppwd="$PWD"
    fi
else
    # file *cannot* exist
    return 1 # failure
fi

# reassemble realpath
echo "$tmppwd"/"${1##*/}"
return 0 # success

}

これを他の関数get_dirname、get_filename、get_stemname、およびvalidate_pathと組み合わせることができます。これらは、GitHubリポジトリでrealpath-libとして見つけることができます(完全な開示-これは私たちの製品ですが、制限なしにコミュニティに無料で提供しています)。また、説明用のツールとしても機能します-十分に文書化されています。

いわゆる「モダンバッシュ」の手法を適用するために最善を尽くしましたが、バッシュは大きなテーマであり、常に改善の余地があると確信しています。Bash 4+が必要ですが、まだ使用されている場合は古いバージョンで動作するようにできます。


1

私の作業は非BSD LinuxとmacOSを使用している人々が使用しているため、ビルドスクリプトでこれらのエイリアスを使用することを選択しました(sed同様の問題があるため含まれています)。

##
# If you're running macOS, use homebrew to install greadlink/gsed first:
#   brew install coreutils
#
# Example use:
#   # Gets the directory of the currently running script
#   dotfilesDir=$(dirname "$(globalReadlink -fm "$0")")
#   alias al='pico ${dotfilesDir}/aliases.local'
##

function globalReadlink () {
  # Use greadlink if on macOS; otherwise use normal readlink
  if [[ $OSTYPE == darwin* ]]; then
    greadlink "$@"
  else
    readlink "$@"
  fi
}

function globalSed () {
  # Use gsed if on macOS; otherwise use normal sed
  if [[ $OSTYPE == darwin* ]]; then
    gsed "$@"
  else
    sed "$@"
  fi
}

homebrew + coreutils依存関係を自動的にインストールするために追加できるオプションのチェック:

if [[ "$OSTYPE" == "darwin"* ]]; then
  # Install brew if needed
  if [ -z "$(which brew)" ]; then 
    /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"; 
  fi
  # Check for coreutils
  if [ -z "$(brew ls coreutils)" ]; then
    brew install coreutils
  fi
fi

私は本当に「グローバル」だと思います。他の人をチェックする必要があります...しかし、それはおそらく80/20のマークに近づきます。


1

説明

coreutilsは、brewそれらのMac OSX実装に対応するGNU / Linuxコアユーティリティをインストールして、それらを使用できるようにするパッケージです

Linuxのcoreutils( "コアユーティリティ")に似ているように見えるプログラムやユーティリティがMac OSXシステムで見つかるかもしれませんが、それらはいくつかの点で異なります(異なるフラグを持つなど)。

これは、これらのツールのMac OSX実装が異なるためです。元のGNU / Linuxのような動作を取得するにはcoreutilsbrewパッケージ管理システムを介してパッケージをインストールできます。

これにより、接頭辞が付いた対応するコアユーティリティがインストールされgます。たとえばの場合readlink、対応するgreadlinkプログラムが見つかります。

作るためにreadlinkGNUのように行うreadlinkgreadlink)の実装、あなたがcoreutilsのをインストールした後、簡単なエイリアスを作ることができます。

実装

  1. brewをインストールする

https://brew.sh/の指示に従ってください

  1. coreutilsパッケージをインストールする

brew install coreutils

  1. エイリアスを作成する

〜/ .bashrc、〜/ .bash_profile、またはbashエイリアスの保持に慣れている場所にエイリアスを配置できます。私は個人的に〜/ .bashrcに私のものを保管します

alias readlink=greadlink

gmv、gdu、gdfなどの他のcoreutilsに同様のエイリアスを作成できます。ただし、macマシンでのGNUの動作は、ネイティブのcoreutilsでの作業に慣れている他のユーザーを混乱させたり、Macシステムで予期しない動作をする可能性があることに注意してください。


0

私が書いたOS X用のrealpathユーティリティと同じ結果を提供することができますreadlink -f


次に例を示します。

(jalcazar@mac tmp)$ ls -l a
lrwxrwxrwx 1 jalcazar jalcazar 11  8 25 19:29 a -> /etc/passwd

(jalcazar@mac tmp)$ realpath a
/etc/passwd


MacPortsを使用している場合は、次のコマンドでインストールできますsudo port selfupdate && sudo port install realpath


0

本当にプラットフォームに依存しないのもこのR-onlinerでしょう

readlink(){ RScript -e "cat(normalizePath(commandArgs(T)[1]))" "$1";}

実際にを模倣するにはreadlink -f <path>、$ 1ではなく$ 2を使用する必要があります。


デフォルトでは、R以外のシステムにはほとんどありません。Macにはまだありません(10.15現在)。これがこの質問に関するものです。
codeniffer

0

POSIX readlink -fシェルスクリプトのPOSIX準拠の実装

https://github.com/ko1nksm/readlinkf

これはPOSIXに準拠しています(バシズムなし)。もも使用しませreadlinkrealpath。GNUと比較して、まったく同じであることを確認しましたreadlink -fテスト結果を参照)。エラー処理と優れたパフォーマンスがあります。から安全に交換できreadlink -fます。ライセンスはCC0なので、どのプロジェクトにも使用できます。

# POSIX compliant version
readlinkf_posix() {
  [ "${1:-}" ] || return 1
  target=$1 max_symlinks=10 CDPATH=''

  [ -e "${target%/}" ] || target=${1%"${1##*[!/]}"} # trim trailing slashes
  [ -d "${target:-/}" ] && target="$target/"

  cd -P . 2>/dev/null || return 1
  while [ "$max_symlinks" -gt 0 ] && max_symlinks=$((max_symlinks - 1)); do
    if [ ! "$target" = "${target%/*}" ]; then
      cd -P "${target%/*}/" 2>/dev/null || break
      target=${target##*/}
    fi

    if [ ! -L "$target" ]; then
      target="${PWD%/}${target:+/}$target"
      printf '%s\n' "${target:-/}"
      return 0
    fi

    # `ls -dl` format: "%s %u %s %s %u %s %s -> %s\n",
    #   <file mode>, <number of links>, <owner name>, <group name>,
    #   <size>, <date and time>, <pathname of link>, <contents of link>
    # https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html
    link=$(ls -dl "$target" 2>/dev/null) || break
    target=${link#*" $target -> "}
  done
  return 1
}

最新のコードを参照してください。修正されている場合があります。


-2

Perlにはreadlink関数があります(Perlでシンボリックリンクをコピーするにはどうすればよいですか?)。これは、OS Xを含むほとんどのプラットフォームで機能します。

perl -e "print readlink '/path/to/link'"

例えば:

$ mkdir -p a/b/c
$ ln -s a/b/c x
$ perl -e "print readlink 'x'"
a/b/c

5
これは、オプションreadlinkなしの-f場合と同じです-再帰なし、絶対パスなし-なので、readlink直接使用することもできます。
mklement0

-2

@キースミスからの答えは無限ループを与えます。

これが私の回答です。これはSunOSでのみ使用します(SunOSはPOSIXとGNUのコマンドをあまり見逃しています)。

これは、$ PATHディレクトリの1つに配置する必要があるスクリプトファイルです。

#!/bin/sh
! (($#)) && echo -e "ERROR: readlink <link to analyze>" 1>&2 && exit 99

link="$1"
while [ -L "$link" ]; do
  lastLink="$link"
  link=$(/bin/ls -ldq "$link")
  link="${link##* -> }"
  link=$(realpath "$link")
  [ "$link" == "$lastlink" ] && echo -e "ERROR: link loop detected on $link" 1>&2 && break
done

echo "$link"


-5

readlinkへのパスは、私のシステムとあなたのシステムで異なります。フルパスを指定してみてください:

/sw/sbin/readlink -f


1
そして何が-正確に-/ sw / sbinと/ usr / binの違いは何ですか?そして、なぜ2つのバイナリが異なるのですか?
troelskn 2009年

4
Aha ..したがって、finkにreadlinkはgnu互換の代替が含まれています。知っておくと便利ですが、他の人のマシンでスクリプトを実行する必要があり、そのためにfinkをインストールするように要求できないため、問題は解決しません。
troelskn 2009

あなたは元の質問に答えていません。回答を書き直してください。
ハイメHablutzel
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.