Bashでファイルパスをどのように正規化しますか?


204

に変身/foo/bar/..したい/foo

これを行うbashコマンドはありますか?


編集:私の実際のケースでは、ディレクトリは存在します。


4
実際に存在するかどう/foo/bar/foo、またはパス名のルールに従って文字列操作の側面のみに関心があるかどうかは重要ですか?
Chen Levy

5
@twalberg ...それはちょっと工夫された...
カミロ・マーティン14

2
@CamiloMartinまったく工夫されていません-それは質問が尋ねることを正確に行います-に変換/foo/bar/../foobashコマンドを使用します。記載されていない他の要件がある場合は、おそらく彼らは...する必要があります
twalberg

14
@twalberg TDDをやりすぎた-_- '
Camilo Martin

回答:


193

パスからファイル名の一部を切り詰めたい場合は、「dirname」と「basename」がお友達で、「realpath」も便利です。

dirname /foo/bar/baz 
# /foo/bar 
basename /foo/bar/baz
# baz
dirname $( dirname  /foo/bar/baz  ) 
# /foo 
realpath ../foo
# ../foo: No such file or directory
realpath /tmp/../tmp/../tmp
# /tmp

realpath 代替案

realpathシェルでサポートされていない場合は、試すことができます

readlink -f /path/here/.. 

また

readlink -m /path/there/../../ 

と同じように機能します

realpath -s /path/here/../../

正規化するためにパスが存在する必要はありません。


5
OS Xソリューションが必要な方は、以下のAdam Lissの回答をご覧ください。
2016年

stackoverflow.com/a/17744637/999943 これは強く関連する答えです!両方のQA投稿に1日で出くわし、それらをリンクしたいと考えました。
phyatt

realpathは2012年にcoreutilsに追加されたようです。github.com/ coreutils / coreutils / commits / master / src / realpath.cでファイル履歴を参照してください。
Noah Lavine 2017年

1
どちらrealpathreadlinkそうおそらくあなたはどちらかまたは両方なし得る、GNUコアユーティリティから来ています。私の記憶が正しければ、MacのreadlinkバージョンはGNUバージョンとは少し異なります:-\
Antoine 'hashar' Musso

100

これを行う直接のbashコマンドがあるかどうかはわかりませんが、通常は

normalDir="`cd "${dirToNormalize}";pwd`"
echo "${normalDir}"

そしてそれはうまくいきます。


9
これにより、ソフトリンクは正常化されますが解決されません。これはバグか機能のいずれかです。:-)
Adam Liss

4
$ CDPATHが定義されている場合にも問題があります。「cd foo」は、現在のディレクトリにある「foo」だけでなく、$ CDPATHのサブディレクトリである「foo」ディレクトリに切り替わるからです。CDPATH = "" cd "$ {dirToNormalize}" && pwd -Pのようにする必要があると思います。
mjs 2009年

7
ティムの答えは間違いなく最も単純で最も移植性があります。CDPATHは扱いやすい:dir = "$(unset CDPATH && cd" $ dir "&& pwd)"
David Blevins

2
rm -rf $normalDirdirToNormalizeが存在しない場合、これは非常に危険です()。
フランクMeulenaar

4
ええ、&&@ DavidBlevinsのコメントのとおりに使用するのがおそらく最善です。
エリアスドルネレス2014

54

お試しくださいrealpath。以下はソース全体です。これにより、パブリックドメインに寄付されます。

// realpath.c: display the absolute path to a file or directory.
// Adam Liss, August, 2007
// This program is provided "as-is" to the public domain, without express or
// implied warranty, for any non-profit use, provided this notice is maintained.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>   
#include <limits.h>

static char *s_pMyName;
void usage(void);

int main(int argc, char *argv[])
{
    char
        sPath[PATH_MAX];


    s_pMyName = strdup(basename(argv[0]));

    if (argc < 2)
        usage();

    printf("%s\n", realpath(argv[1], sPath));
    return 0;
}    

void usage(void)
{
    fprintf(stderr, "usage: %s PATH\n", s_pMyName);
    exit(1);
}

1
これは標準のbashインストールの一部として含まれていますか?私たちのシステム(RHELのbash 3.00.15(1))で「コマンドが見つかりません」
Tim Whitcomb

4
readlinkはgnu.org/software/coreutilsですが、realpathは次のパッケージから取得されます:packages.debian.org/unstable/utils/realpath
Kent Fredric

8
Centos

4
「ボーナス:そのbashコマンドであり、どこでも利用可能です!」という部分を実際に打ち消す必要があります。についての部分realpath。それはたまたま私のお気に入りですが、ソースからツールをコンパイルする代わりに。それはすべてヘビー級であり、たいていの場合あなたが望むだけですreadlink -f...ところで、readlinkまた、bashの組み込みではなくcoreutils、Ubuntuの一部です。
Tomasz Gandor 14年

4
これをパブリックドメインに寄付しているとおっしゃっていましたが、ヘッダーにも「非営利目的の使用」と表示されています。本当にパブリックドメインに寄付するつもりですか。それは...それは、商業営利目的のためだけでなく、非営利のために使用することができることを意味だろう
me_and

36

ポータブルで信頼性の高いソリューションは、Pythonを使用することです。これは、ほとんどすべての場所(Darwinを含む)にプリインストールされています。次の2つのオプションがあります。

  1. abspath 絶対パスを返しますが、シンボリックリンクを解決しません:

    python -c "import os,sys; print(os.path.abspath(sys.argv[1]))" path/to/file

  2. realpath 絶対パスを返し、その際にシンボリックリンクを解決し、正規パスを生成します。

    python -c "import os,sys; print(os.path.realpath(sys.argv[1]))" path/to/file

いずれの場合path/to/fileも、相対パスまたは絶対パスのいずれかになります。


7
おかげで、うまくいったのはそれだけでした。readlinkやrealpathはOS Xでは使用できません。Pythonはほとんどのプラットフォームで使用できます。
ソリン

1
明確にするために、readlinkOS Xで利用でき-fます。オプションはありません。ここで説明する移植可能な回避策。
StvnW 2014

3
リンクをたどらない場合、これが唯一の健全な解決策であるということは、文字通り私の心を揺さぶります。Unixの方法私の足。
DannoHung、2016年

34

coreutilsパッケージのreadlinkユーティリティを使用します。

MY_PATH=$(readlink -f "$0")

1
BSDには-fフラグがありません。これは、最新のMacOS Mojaveおよび他の多くのシステムでも失敗することを意味します。移植性が必要な場合は-fの使用を忘れてください。多くのOSが影響を受けます。
ソリン

1
@sorin。問題はMacについてではなく、Linuxについてです。
mattalxndr 2018年

14

readlink絶対パスを取得するためのbash標準です。また、パスまたはパスが存在しない場合にフラグを指定すると、空の文字列が返されるという利点もあります。

存在するかもしれないし存在しないかもしれないが、親は存在するディレクトリへの絶対パスを取得するには、以下を使用します。

abspath=$(readlink -f $path)

すべての親と一緒に存在しなければならないディレクトリへの絶対パスを取得するには:

abspath=$(readlink -e $path)

指定されたパスを正規化し、存在する場合はシンボリックリンクをたどりますが、それ以外の場合は欠落しているディレクトリを無視し、とにかくパスを返すだけです。

abspath=$(readlink -m $path)

唯一の欠点は、readlinkがリンクをたどることです。リンクをたどらない場合は、次の代替規則を使用できます。

abspath=$(cd ${path%/*} && echo $PWD/${path##*/})

これは、$ pathのディレクトリ部分にchdirし、$ pathのファイル部分と共に現在のディレクトリを出力します。chdirに失敗すると、空の文字列とstderrでエラーが発生します。


7
readlinkそれが利用可能な場合は、良いオプションです。OS Xバージョンは-eまたは-fオプションをサポートしていません。最初の3つの例では$path、ファイル名のスペースまたはワイルドカードを処理するために、二重引用符で囲む必要があります。パラメータ展開の+1ですが、これにはセキュリティ上の脆弱性があります。pathが空の場合、これはcdホームディレクトリになります。二重引用符が必要です。abspath=$(cd "${path%/*}" && echo "$PWD/${path##*/}")
toxalot 2014年

これはほんの一例です。あなたがセキュリティに熱中しているなら、あなたは本当にbashや他のシェルバリアントをまったく使用すべきではありません。また、bashには、プラットフォーム間の互換性に関して独自の問題があります。また、メジャーバージョン間の機能変更に関する問題もあります。OSXは、BSDに基づいていることは言うまでもなく、シェルスクリプトに関連する問題がある多くのプラットフォームの1つにすぎません。真にマルチプラットフォームになる必要がある場合は、POSIXに準拠する必要があるため、パラメーターの拡張は実際にはありません。SolarisまたはHP-UXをしばらく見てください。
クレイグ

6
ここではいかなる違反も意味しませんが、このようなあいまいな問題を指摘することは重要です。私はこの些細な問題への迅速な回答を望んでいるだけで、上記のコメントがなければ、すべての入力でそのコードを信頼していました。これらのbashディスカッションでOS-Xをサポートすることも重要です。残念ながらOS-Xではサポートされていないコマンドがたくさんあります。多くのフォーラムでは、Bashについて議論する際に当然のことと考えています。つまり、後でではなく早く対処しない限り、多くのクロスプラットフォームの問題が発生し続けることになります。
2014

13

古い質問ですが、シェルレベルでフルパス名を処理する場合、もっと簡単な方法があります。

   abspath = "$(cd" $ path "&& pwd)"

cdはサブシェルで発生するため、メインスクリプトには影響しません。

シェル組み込みコマンドが-Lと-Pを受け入れるとすると、2つのバリエーションがあります。

   abspath = "$(cd -P" $ path "&& pwd -P)"#解決されたシンボリックリンクを含む物理パス
   abspath = "$(cd -L" $ path "&& pwd -L)"#シンボリックリンクを保持する論理パス

個人的には、何らかの理由でシンボリックリンクに魅了されない限り、この後者のアプローチはほとんど必要ありません。

参考:スクリプトが現在のディレクトリを後で変更した場合でも機能するスクリプトの開始ディレクトリを取得する方法のバリエーション。

name0 = "$(basename" $ 0 ")"; #スクリプトのベース名
dir0 = "$(cd" $(dirname "$ 0") "&& pwd)"; #絶対開始ディレクトリ

CDを使用すると、スクリプトが./script.shなどのコマンドによって実行され、cd / pwdを使用せずに..


8

Adam Lissが述べたようにrealpath、すべてのディストリビューションにバンドルされているわけではありません。これが最善の解決策なので、これは残念です。提供されているソースコードは素晴らしいので、おそらく今から使い始めるでしょう。これは私が今まで使用してきたものですが、完全を期すためにここで共有します。

get_abs_path() {
     local PARENT_DIR=$(dirname "$1")
     cd "$PARENT_DIR"
     local ABS_PATH="$(pwd)"/"$(basename "$1")"
     cd - >/dev/null
     echo "$ABS_PATH"
} 

シンボリックリンクを解決したい場合は、単にに置き換えpwdてくださいpwd -P


pwd -Pこの場合のオプションの1つの問題... $(basename "$1")別のディレクトリにあるファイルへのシンボリックリンクがどうなるかを検討してください。pwd -P唯一のベース名部分パスのディレクトリ部分にシンボリックリンクを解決しますが、ありません。
toxalot 2014年

7

私の最近の解決策は:

pushd foo/bar/..
dir=`pwd`
popd

Tim Whitcombの回答に基づいています。


引数がディレクトリでない場合、これは失敗すると思います。/ usr / bin / javaがどこにつながるのか知りたいと思いますか?
エドワードフォーク

1
ファイルであることがわかっている場合はpushd $(dirname /usr/bin/java)、試してみてください。
Schmunk 2016年

5

正確な回答ではなく、おそらくフォローアップの質問(元の質問は明確ではなかった):

readlink実際にシンボリックリンクを追跡したい場合は問題ありません。単に正規化するためのユースケースもある./し、../そして//、純粋に構文的に行うことができる配列、ことなくシンボリックリンクをcanonicalizingは。readlinkこれは良くありませんrealpath

for f in $paths; do (cd $f; pwd); done

既存のパスでは機能しますが、他のパスでは機能しません。

sed(スクリプトは、繰り返しシーケンスを置き換えることはできませんことを除いて、良い賭けのように見えるだろう/foo/bar/baz/../..- > /foo/bar/..> - /fooすべてのシステム上で前提としても安全ではないPerlの、のようなものを使用して、またはの出力を比較するために、いくつかの醜いループを使用せず)sedへのその入力。

FWIW、Javaを使用したワンライナー(JDK 6+):

jrunscript -e 'for (var i = 0; i < arguments.length; i++) {println(new java.io.File(new java.io.File(arguments[i]).toURI().normalize()))}' $paths

realpathには、-sシンボリックリンクを解決せず、への参照のみを解決し/.//../余分な/文字を削除するオプションがあります。-mオプションと組み合わせると、realpathファイル名のみを操作し、実際のファイルには影響しません。それは完璧なソリューションのように聞こえます。しかし、悲しいかな、realpathまだ多くのシステムで欠落しています。
toxalot 2014年

..シンボリックリンクが含まれている場合、コンポーネントの削除は構文的に実行できません。 /one/two/../threeがへのシンボリックリンクである/one/three場合twoと同じではありません/foo/bar
jrw32982は、20:12にMonica

@ jrw32982はい、私の応答で述べたとおり、これはシンボリックリンクの正規化が不要または必要でない場合の使用例です。
Jesse Glick

@JesseGlickシンボリックリンクを正規化するかどうかだけではありません。あなたのアルゴリズムは実際には間違った答えを出します。正解を得るには、関係するシンボリックリンクがない(または特定の形式のシンボリックリンクである)ことをアプリオリに知る必要があります。あなたの答えは、それらを正規化したくない、パスに関与するシンボリックリンクがないということではありません。
jrw32982は2015

固定された既存のディレクトリ構造を想定せずに正規化を実行する必要があるユースケースがあります。URIの正規化も同様です。これらのケースでは、結果が後で適用されるディレクトリの近くにシンボリックリンクが存在する場合、結果が一般に正しくないことは本質的な制限です。
Jesse Glick

5

私はパーティーに遅れましたが、これは私がこのようなスレッドの束を読んだ後に作成した解決策です:

resolve_dir() {
        (builtin cd `dirname "${1/#~/$HOME}"`'/'`basename "${1/#~/$HOME}"` 2>/dev/null; if [ $? -eq 0 ]; then pwd; fi)
}

これにより、$ 1の絶対パスが解決され、〜でうまく機能し、シンボリックリンクが存在するパスに維持されます。ディレクトリスタックが混乱することはありません。存在しない場合は、フルパスを返すか、何も返しません。$ 1がディレクトリであることを想定しており、そうでない場合はおそらく失敗しますが、これは簡単に確認できます。


4

おしゃべりで、少し遅い答え。私は古いRHEL4 / 5に行き詰まっているので、それを書く必要があります。絶対リンクと相対リンクを処理し、//、/。/、somedir /../エントリを簡略化します。

test -x /usr/bin/readlink || readlink () {
        echo $(/bin/ls -l $1 | /bin/cut -d'>' -f 2)
    }


test -x /usr/bin/realpath || realpath () {
    local PATH=/bin:/usr/bin
    local inputpath=$1
    local changemade=1
    while [ $changemade -ne 0 ]
    do
        changemade=0
        local realpath=""
        local token=
        for token in ${inputpath//\// }
        do 
            case $token in
            ""|".") # noop
                ;;
            "..") # up one directory
                changemade=1
                realpath=$(dirname $realpath)
                ;;
            *)
                if [ -h $realpath/$token ] 
                then
                    changemade=1
                    target=`readlink $realpath/$token`
                    if [ "${target:0:1}" = '/' ]
                    then
                        realpath=$target
                    else
                        realpath="$realpath/$target"
                    fi
                else
                    realpath="$realpath/$token"
                fi
                ;;
            esac
        done
        inputpath=$realpath
    done
    echo $realpath
}

mkdir -p /tmp/bar
(cd /tmp ; ln -s /tmp/bar foo; ln -s ../.././usr /tmp/bar/link2usr)
echo `realpath /tmp/foo`

3

GitHubに無料で自由に使用できるように配置した新しいBashライブラリ製品realpath-libをお試しください。完全に文書化されており、優れた学習ツールになります。

ローカル、相対、絶対パスを解決し、Bash 4+以外の依存関係はありません。だから、それはどこでも動作するはずです。それは無料で、クリーンで、シンプルで有益です。

できるよ:

get_realpath <absolute|relative|symlink|local file path>

この関数はライブラリのコアです:

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への関数も含まれています。プラットフォーム間で試してみて、改善にご協力ください。


2

の問題realpathは、BSD(またはOSX)では利用できないことです。Linux Journalのかなり古い(2009)記事から抜粋した簡単なレシピは次のとおりです。これは非常に移植性があります。

function normpath() {
  # Remove all /./ sequences.
  local path=${1//\/.\//\/}

  # Remove dir/.. sequences.
  while [[ $path =~ ([^/][^/]*/\.\./) ]]; do
    path=${path/${BASH_REMATCH[0]}/}
  done
  echo $path
}

このバリアントもパスが存在する必要がないことに注意してください。


ただし、これはシンボリックリンクを解決しません。Realpathは、ルートから始まるパスを処理し、進行するにつれてシンボリックリンクに従います。これは、親参照を折りたたむだけです。
Martijn Pieters

2

@Andreの回答に基づいて、誰かがループフリーの完全に文字列操作ベースのソリューションを使用している場合に備えて、少し良いバージョンがあるかもしれません。また、realpathまたはを使用することのマイナス面であるシンボリックリンクを逆参照したくない場合にも役立ちreadlink -fます。

bashバージョン3.2.25以降で動作します。

shopt -s extglob

normalise_path() {
    local path="$1"
    # get rid of /../ example: /one/../two to /two
    path="${path//\/*([!\/])\/\.\./}"
    # get rid of /./ and //* example: /one/.///two to /one/two
    path="${path//@(\/\.\/|\/+(\/))//}"
    # remove the last '/.'
    echo "${path%%/.}"
}

$ normalise_path /home/codemedic/../codemedic////.config
/home/codemedic/.config

これはいいアイデアですが、さまざまなバージョンのbashでこれを機能させるために20分も無駄にしました。これが機能するためにはextglobシェルオプションをオンにする必要があることがわかりました。デフォルトではそうではありません。bash機能に関しては、必要なバージョンとデフォルト以外のオプションの両方を指定することが重要です。これらの詳細はOSによって異なるためです。たとえば、Mac OSX(Yosemite)の最近のバージョンには、古いバージョンのbash(3.2)しか付属していません。
drwatsoncode

申し訳ありませんが、@ ricovox; それらを更新しました。私はあなたが持っているBashの正確なバージョンを知りたいと思っています。上記の式(更新)は、bash 3.2.25に付属するCentOS 5.8で機能します
ϹοδεMεδιϲ

混乱させて申し訳ありません。このコードは、extgloblをオンにすると、私のバージョンのMac OSX bash(3.2.57)で動作しました。bashのバージョンに関する私のメモは、より一般的なものでした(これは、実際にはbashの正規表現に関する別の回答にさらに当てはまります)。
drwatsoncode

2
私はあなたの答えに感謝します。自分のベースとして使った。ちなみに私はあなたの失敗するいくつかのケースに気づきました:(1)相対パスhello/../world(2)ファイル名のドット/hello/..world(3)ダブルスラッシュの/hello//../world後のドット(4)ダブルスラッシュの前または後のドット /hello//./worldまたは /hello/.//world (5)現在の後の親:/hello/./../world/ (6)親親の後: /hello/../../world、など- これらの一部は、パスを変更しなくなるまでループを使用して修正することで修正できます。(また削除dir/../、ではない /dir/..が、除去dir/..端部から)
drwatsoncode

0

loveborgの優れたpythonスニペットに基づいて、私はこれを書きました:

#!/bin/sh

# Version of readlink that follows links to the end; good for Mac OS X

for file in "$@"; do
  while [ -h "$file" ]; do
    l=`readlink $file`
    case "$l" in
      /*) file="$l";;
      *) file=`dirname "$file"`/"$l"
    esac
  done
  #echo $file
  python -c "import os,sys; print os.path.abspath(sys.argv[1])" "$file"
done

0
FILEPATH="file.txt"
echo $(realpath $(dirname $FILEPATH))/$(basename $FILEPATH)

これは、ファイルが存在しない場合でも機能します。ファイルを含むディレクトリが存在する必要があります。


GNUのrealpathは、あなたが使用しない限り、いずれかの存在するパスの最後の要素を必要としないrealpath -e
マルタインピータース

0

3つすべてを実行するソリューションが必要でした。

  • ストックMacで作業します。realpathそしてreadlink -fアドオンです
  • シンボリックリンクを解決する
  • エラー処理がある

#1と#2の両方を含む回答はありませんでした。#3を追加して、他のヤクの毛刈りを保存します。

#!/bin/bash

P="${1?Specify a file path}"

[ -e "$P" ] || { echo "File does not exist: $P"; exit 1; }

while [ -h "$P" ] ; do
    ls="$(ls -ld "$P")"
    link="$(expr "$ls" : '.*-> \(.*\)$')"
    expr "$link" : '/.*' > /dev/null &&
        P="$link" ||
        P="$(dirname "$P")/$link"
done
echo "$(cd "$(dirname "$P")"; pwd)/$(basename "$P")"

引用を完全に実行するために、パスにねじれたスペースがある短いテストケースを次に示します。

mkdir -p "/tmp/test/ first path "
mkdir -p "/tmp/test/ second path "
echo "hello" > "/tmp/test/ first path / red .txt "
ln -s "/tmp/test/ first path / red .txt " "/tmp/test/ second path / green .txt "

cd  "/tmp/test/ second path "
fullpath " green .txt "
cat " green .txt "

0

私はこれが古代の問題であることを知っています。私はまだ代替案を提供しています。最近、同じ問題に遭遇しましたが、それを行うための既存の移植可能なコマンドは見つかりませんでした。だから私はトリックを行うことができる関数を含む次のシェルスクリプトを書きました。

#! /bin/sh                                                                                                                                                

function normalize {
  local rc=0
  local ret

  if [ $# -gt 0 ] ; then
    # invalid
    if [ "x`echo $1 | grep -E '^/\.\.'`" != "x" ] ; then
      echo $1
      return -1
    fi

    # convert to absolute path
    if [ "x`echo $1 | grep -E '^\/'`" == "x" ] ; then
      normalize "`pwd`/$1"
      return $?
    fi

    ret=`echo $1 | sed 's;/\.\($\|/\);/;g' | sed 's;/[^/]*[^/.]\+[^/]*/\.\.\($\|/\);/;g'`
  else
    read line
    normalize "$line"
    return $?
  fi

  if [ "x`echo $ret | grep -E '/\.\.?(/|$)'`" != "x" ] ; then
    ret=`normalize "$ret"`
    rc=$?
  fi

  echo "$ret"
  return $rc
}

https://gist.github.com/bestofsong/8830bdf3e5eb9461d27313c3c282868c


0

これを処理するための組み込み専用関数を作成し、可能な限り最高のパフォーマンスに焦点を合わせました(楽しみのために)。シンボリックリンクを解決しないため、基本的にはと同じrealpath -smです。

## A bash-only mimic of `realpath -sm`. 
## Give it path[s] as argument[s] and it will convert them to clean absolute paths
abspath () { 
  ${*+false} && { >&2 echo $FUNCNAME: missing operand; return 1; };
  local c s p IFS='/';  ## path chunk, absolute path, input path, IFS for splitting paths into chunks
  local -i r=0;         ## return value

  for p in "$@"; do
    case "$p" in        ## Check for leading backslashes, identify relative/absolute path
    '') ((r|=1)); continue;;
    //[!/]*)  >&2 echo "paths =~ ^//[^/]* are impl-defined; not my problem"; ((r|=2)); continue;;
    /*) ;;
    *)  p="$PWD/$p";;   ## Prepend the current directory to form an absolute path
    esac

    s='';
    for c in $p; do     ## Let IFS split the path at '/'s
      case $c in        ### NOTE: IFS is '/'; so no quotes needed here
      ''|.) ;;          ## Skip duplicate '/'s and '/./'s
      ..) s="${s%/*}";; ## Trim the previous addition to the absolute path string
      *)  s+=/$c;;      ### NOTE: No quotes here intentionally. They make no difference, it seems
      esac;
    done;

    echo "${s:-/}";     ## If xpg_echo is set, use `echo -E` or `printf $'%s\n'` instead
  done
  return $r;
}

注:パスの先頭//にある2つの二重スラッシュは実装定義の動作であるため、この関数はで始まるパスを処理しません。ただし、、、/などは問題なく処理さ///れます。

この関数はすべてのエッジケースを適切に処理するようですが、まだ扱っていないものがあるかもしれません。

パフォーマンスに関する注意:何千もの引数を指定して呼び出すと、abspath実行速度がの約10倍になりrealpath -smます。単一の引数で呼び出されたabspath場合realpath -sm、私のマシンよりも110倍以上速く実行されます。これは、ほとんどの場合、毎回新しいプログラムを実行する必要がないためです。


-1

今日、statコマンドを使用してパスを解決できることがわかりました。

したがって、「〜/ Documents」のようなディレクトリの場合:

これを実行できます:

stat -f %N ~/Documents

完全なパスを取得するには:

/Users/me/Documents

シンボリックリンクの場合、%Y形式オプションを使用できます。

stat -f %Y example_symlink

次のような結果を返す可能性があります:

/usr/local/sbin/example_symlink

* NIXの他のバージョンでは書式設定オプションが異なる場合がありますが、これらはOSXで動作しました。


1
stat -f %N ~/Documentsラインが赤ニシンです...あなたのシェルが交換され~/Documents/Users/me/Documents、そしてstatちょうどその引数の逐語的に印刷しています。
danwyand 2015年

-4

を使用した簡単な解決策node.js

#!/usr/bin/env node
process.stdout.write(require('path').resolve(process.argv[2]));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.