OS Xから任意のファイルの絶対パスを取得する方法


18

私は、OS X上のファイルへの絶対パスおよび正規化パスを見つけるためにBash内で使用できる単純なコマンドを探しています(Linuxの「readlink -f」に似ています)。

次のサンプルbashセッションでは、「abspath」という名前の[架空の]ユーティリティについて説明します。このユーティリティは、目的の動作を示します。

$ pwd
/Users/guyfleegman

$ ls -lR
drwxr-xr-x  4 guyfleegman  crew  136 Oct 30 02:09 foo

./foo:
-rw-r--r--  1 guyfleegman  crew  0 Oct 30 02:07 bar.txt
lrwxr-xr-x  1 guyfleegman  crew  7 Oct 30 02:09 baz.txt -> bar.txt


$ abspath .
/Users/guyfleegman

$ abspath foo
/Users/guyfleegman/foo

$ abspath ./foo/bar.txt
/Users/guyfleegman/foo/bar.txt

$ abspath foo/baz.txt
/Users/guyfleegman/foo/baz.txt

上記の例での `` abspath'`の最後の呼び出しと同様に、シンボリックリンクを自動的に解決しなかった方がいいと思いますが、ここではあまり気にしません。


回答:


16
function abspath() { pushd . > /dev/null; if [ -d "$1" ]; then cd "$1"; dirs -l +0; else cd "`dirname \"$1\"`"; cur_dir=`dirs -l +0`; if [ "$cur_dir" == "/" ]; then echo "$cur_dir`basename \"$1\"`"; else echo "$cur_dir/`basename \"$1\"`"; fi; fi; popd > /dev/null; }

例:

abspath / => /

abspath /.DS_Store => /.DS_Store

abspath ~ => /Users/mschrag

cd /tmp; abspath . => /tmp

cd /; abspath .DS_Store => /.DS_Store

11

これを行うbuildinコマンドはないと思います。ジェシー・ウィルソンはこのためのbashスクリプトを書きました:

#!/bin/bash
cd -P -- "$(dirname -- "$1")" &&
printf '%s\n' "$(pwd -P)/$(basename -- "$1")"

ただし、(printing )やand (printing with )の/ような直下のパスではうまく機能しません。修正してみましたが、bash-fuが足りないため失敗しました。/etc//etc.../cwd/.

私の提案は次のとおりです。

#!/usr/bin/env python
import os.path
import sys

for arg in sys.argv[1:]:
    print os.path.abspath(arg)

/usr/bin/abspathまたはそのようなものとして保存し、実行可能にします。サンプル出力:

Servus08:~ danielbeck$ abspath .
/Users/danielbeck
Servus08:~ danielbeck$ abspath /tmp
/tmp
Servus08:~ danielbeck$ abspath Documents
/Users/danielbeck/Documents
Servus08:~ danielbeck$ abspath . /tmp Documents
/Users/danielbeck
/tmp
/Users/danielbeck/Documents

シンボリックリンクの解決必要な場合は、次のようにprint行を変更します。

    print os.path.realpath(os.path.abspath(arg))

これを取得するには:

Servus08:~ danielbeck$ abspath . /tmp Documents
/Users/danielbeck
/private/tmp
/Users/danielbeck/Documents

1
あなたは最初のシェルベースのアプローチで正しい軌道に乗っていると思いますが、これを行うために別の言語を使用すると、追加の依存関係が導入され、GNUのバージョンの `readlink (1) 'OS Xで(これができると仮定します。まだ確認していません)。
マイケルウェナー

2
@MichaelあなたはGNU readlinkを搭載したシステムかOS Xのどちらかにいますか?OS Xにはすぐに使えるPythonがあります。理論的には、これは新しい依存関係であり、実際にはそうではありません。とにかく、それは私があなたに提供できるすべてです。
ダニエルベック

あなたが暗示している実用的なアプローチは、過度に単純化されていても称賛に値します。いずれにせよ、純粋にbashで書かれたものの代わりにこのアプローチをとる場合(これは絶対に実行可能であり、他に何も依存しません-1行で簡単に実行することはできません)、Pythonはおそらく最良の選択ではありません。PerlとRuby(おそらくPHP)は、実際のスクリプトファイルを作成することなく、コマンドラインで簡単にこれを行うことができます。
マイケルウェナー

1
@マイケル:本当ですが、それは私がコメントしていたことではありません。Jesse Wilsonによる純粋なbashで記述された90%のソリューションと、なぜ90%だけであるかの分析を提供します。それがあなたにとって問題でないなら、それは大丈夫です。また、Pythonでのもう少し複雑な100%ソリューションも紹介しました。他のスクリプト言語のほうが簡潔かもしれませんが(Perlの悪名高い:-))、コマンドを保存するには追加のファイルが必要です。それとも、使用するたびに書き出すのですか?それが、複数のパラメーターを処理するための複数行機能を追加した理由でもあります。1行または2行で違いはありません。
ダニエルベック

2
@ Michael、OS XでPythonが良い選択ではないのはなぜですか?このように、実際にはPythonスクリプトなコマンドでさえ船file /usr/bin/xattr
Arjan

8

1つのオプションは、単にcoreutilsをインストールして使用することgreadlink -fです。シンボリックリンクを解決し、存在する場合/Foo/または~/foo.txt存在しない/Foo/foo.txt場合/Foo/は動作しますが、存在しない場合は動作しません。

$ brew install coreutils
$ greadlink -f /etc
/private/etc
$ greadlink -f ~/Documents/
/Users/lauri/Documents
$ greadlink -f ..
/Users
$ greadlink -f //etc/..////
/private
$ greadlink -f /Foo
/Foo
$ greadlink -f /Foo/foo.txt
$ 

これはシンボリックリンクを解決せず、/Foo/foo.txtどちらでも機能しません。

abspath() {
  if [ -d "$1" ]; then
    ( cd "$1"; dirs -l +0 )
  else
    ( cd "$(dirname "$1")"; d=$(dirs -l +0); echo "${d%/}/${1##*/}" )
  fi
}

abspath /etc # /etc
abspath ~/Foo/foo.txt # doesn't work
abspath ~/Foo # works
abspath .
abspath ./
abspath ../
abspath ..
abspath /
abspath ~
abspath ~/
abspath ~/Documents
abspath /\"\ \'
abspath /etc/../etc/
abspath /private//etc/
abspath /private//
abspath //private # //private
abspath ./aa.txt
abspath aa.tar.gz
abspath .aa.txt
abspath /.DS_Store
abspath ~/Documents/Books/

dirs -lチルダ展開を実行します。dirs +0スタックに他のディレクトリがある場合、最上位のディレクトリのみを出力します。


2

pythonまたはrubyでできると思います。

$ ruby -e 'puts File.expand_path("~/somepath")'

またはそれをコマンドにする

#!/usr/bin/env ruby
puts File.expand_path(ARGV[0])

ダニエル・ベックの答えに対する私の以前のコメントもここに当てはまります(純粋にBash-yのソリューションを好むでしょう)が、これを達成するために別の言語を使用することに頼るなら、その簡潔さのためにこれまでのところあなたのソリューションが最高です :)また、おそらくrubyの呼び出しをラップして(たとえば、関数abspath(){ruby -e "puts File.expand_path( '$ 1')";})、それを `.profile 'に入れます。
マイケルウェナー

1

perl用のFile :: Specモジュールがインストールされている場合、これを行うことができます。

perl -MFile::Spec -e 'print File::Spec->rel2abs("../however/complex/../you/want/to.get"), "\n"'

0

bash / shスクリプトの場合、次の再帰関数を使用できます。

canonical_readlink ()
{
    cd `dirname $1`;
    __filename=`basename $1`;
    if [ -h "$__filename" ]; then
        canonical_readlink `readlink $__filename`;
    else
        echo "`pwd -P`";
    fi
}

answer=$(canonical_readlink $0)

一部の変数とコマンド置換は適切に引用されません。のような変数名の代わりにローカル変数を使用できます__filename。スクリプトは現在、dirnameとにかく同じように動作します。
Lri

0

OSX用の次のライブラリをインストールします。

brew install coreutils

greadlink -f file.txt

0

coreutilsのインストールがオプションではない場合、以下はシンボリックリンクのコンボを処理します。そして..そしてGNU realpathのようにファイルとフォルダで動作します:

#!/usr/bin/env bash
realpath()
{
    if ! pushd $1 &> /dev/null; then 
        pushd ${1##*/} &> /dev/null
        echo $( pwd -P )/${1%/*}
    else
        pwd -P
    fi
    popd > /dev/null
}

ただし、realpathの--relative-toはサポートしていません。これには/programming//a/12498485/869951が必要です。


0

制約がMacOS(当時はOS X)であるとすると、PHPはデフォルトで使用可能です。これにより、ファイルのルートディレクトリが返されます。削除dirnameしてファイルも取得します。

export SOURCE_DIRECTORY="$(php -r 'echo dirname(realpath($argv[1]));' -- "${BASH_SOURCE[0]}")"
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.