ファイルへの絶対パスを出力するbash / fishコマンド


448

質問:フィードしたファイルの絶対パスを出力する単純なsh / bash / zsh / fish / ...コマンドはありますか?

使用ケース:私はディレクトリにいる/a/bと私は、ファイルへのフルパスを印刷したいのですがc、私は簡単に別のプログラムに貼り付けできるように、コマンドラインで:/a/b/c。単純ですが、これを行う小さなプログラムを使用すると、長いパスを処理することになると、おそらく5秒ほど節約できます。そのため、これを行うための標準ユーティリティが見つからないことに驚いています。本当にありませんか?

次に、abspath.pyの実装例を示します。

#!/usr/bin/python
# Author: Diggory Hardy <diggory.hardy@gmail.com>
# Licence: public domain
# Purpose: print the absolute path of all input paths

import sys
import os.path
if len(sys.argv)>1:
    for i in range(1,len(sys.argv)):
        print os.path.abspath( sys.argv[i] )
    sys.exit(0)
else:
    print >> sys.stderr, "Usage: ",sys.argv[0]," PATH."
    sys.exit(1)

@DennisWilliamsonの回答(-mオプションを使用)は、(通常)移植性が高く、存在しないファイルを処理するのに優れていると主張します。
TTT

またはFlimmの答え。どちらも優れたソリューションです。しかし Bannier'sは私の元の質問に最もよく答えます。
dhardy 2014年

3
OSXユーザー:この回答を
Ian

回答:


561

お試しくださいrealpath

$ realpath example.txt
/home/username/example.txt

133
+1、とてもいいプログラム。ただし、これは外部コマンド(シェル組み込みではない)であり、デフォルトですべてのシステムに存在するわけではないことに注意してください。つまり、インストールする必要がある場合があります。Debianでは、同じ名前の別のパッケージにあります。
Roman Cheplyaka

5
私は自分のパスに追加realpath:からなるgithub.com/westonruter/misc-cli-tools/blob/master/realpath
ウェストンRuter

1
@Flimm:相対パスを指定しても、有効なパスが提供されます。ファイルの存在について知りたい場合は、テストなどの別のツールを使用してください。
ベンジャミンバニエ2013

14
@Dalin:coreutilsをインストールしてみてください。バイナリの名前はgrealpathです。
Toni Penya-Alba 2014

5
このツールはGNU coreutils 8.15(2012年)で導入されたので、非常に新しいものです。
marbu 14

317

readlinkシンボリックリンクを解決する方法を試してください。

readlink -e /foo/bar/baz

50
「-e」ではなく「-f」を使用して、存在しないファイルの絶対パスを確認できるようにします。
hluk

5
これは私にとっては最も単純なようですが、移植性もあります。readlinkはgnu coreutilsのポートであるため、一部の組み込みのものを除いて、ほとんどすべてのLinuxディストリビューションにインストールされます。
catphive 2010年

14
それ-mが使用するのに最適なオプションだと私には思われます。
マットジョイナー

1
@ダリン:/usr/bin/readlinkマーベリックスで。それとも、それらのオプションがOS Xにないということですか?BSDバージョンの発育阻害のようです...:p
iconoclast 14

14
@iconoclastこれらのオプションはOSXでは使用できません。また、BSDのreadlinkマンページに従って:only the target of the symbolic link is printed. If the given argument is not a symbolic link, readlink will print nothing and exit with an errorなので、readlinkはこの目的でOSXで機能しません
SnoringFrog

257
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"

8
すべてのものを引用することを忘れないでください。理由がわからない場合は、ファイルでプログラムを試してくださいa b(aとbの間に2つのスペースがあり、SOがそれらの1つを食べます)。
Roman Cheplyaka

1
これを「/」で試してみると、「///」に変わります
George

35
readlinkとrealpathはPOSIXではないため、実行可能ファイルを作成してコンパイルする必要のないこれまでの唯一のPOSIXソリューション
Ciro Santilli郝海东冠状病六四事件法轮功

25
私は以前、OS Xでfunction realpath { echo $(cd $(dirname $1); pwd)/$(basename $1); }自分をrealpathコマンド(現在受け入れられている回答)にしていました。
James Bedford、

1
私は、スクリプトのログファイル名を定義するには、このメソッドを使用:LOG=$(echo $(cd $(dirname $0); pwd)/$(basename $0 .sh).log)
DrStrangepork

84

忘れるreadlinkrealpathどのまたはシステムにインストールしてもしなくてもよいです。

上記のdogbaneの答えを拡張すると、関数として表現されます。

#!/bin/bash
get_abs_filename() {
  # $1 : relative filename
  echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
}

その後、次のように使用できます。

myabsfile=$(get_abs_filename "../../foo/bar/file.txt")

どのようにそしてなぜそれは機能しますか?

このソリューションは、Bash組み込みpwdコマンドが引数なしで呼び出されたときに現在のディレクトリの絶対パスを出力するという事実を利用しています。

なぜこのソリューションが好きなのですか?

それは移植性があり、どちらも必要としないreadlinkか、またはrealpath特定のLinux / Unixディストリビューションのデフォルトのインストールでは存在しないことがよくあります。

dirが存在しない場合はどうなりますか?

上記のように、指定されたディレクトリパスが存在しない場合、関数は失敗し、stderrに出力されます。これはあなたが望むものではないかもしれません。関数を展開して、その状況を処理できます。

#!/bin/bash
get_abs_filename() {
  # $1 : relative filename
  if [ -d "$(dirname "$1")" ]; then
    echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
  fi
}

親ディレクトリが存在しない場合、空の文字列を返します。

末尾の「..」または「。」をどのように処理しますか 入力中?

ええと、それはその場合絶対パスを与えますが、最小パスではありません。次のようになります。

/Users/bob/Documents/..

「..」を解決するには、次のようなスクリプトを作成する必要があります。

get_abs_filename() {
  # $1 : relative filename
  filename=$1
  parentdir=$(dirname "${filename}")

  if [ -d "${filename}" ]; then
      echo "$(cd "${filename}" && pwd)"
  elif [ -d "${parentdir}" ]; then
    echo "$(cd "${parentdir}" && pwd)/$(basename "${filename}")"
  fi
}

素晴らしい機能ですが、どうやらあなたは質問を理解していませんでした。スクリプトではなく、インタラクティブな使い方が欲しかった。
ダーディ2014年

3
私はそれを追加したいと思いますrealpathまた、のようなツールが含まれていcoreutilsのパッケージ、から来ているwhotouchまたはをcat。これはGNUツールのかなり標準的なセットなので、ほとんどすべてのLinuxベースのマシンにインストールされていることを確信できます。それは正しいことです。2つの問題があります。i)デフォルトのインストールで見逃す可能性があります非GNU unixシステム(OpenBSDのような)ii)このツールはバージョン8.15で導入されたため(2012年からかなり新しいため)、長期安定システム(RHEL 6など)では見逃されます。
marbu 14

1
少なくとも、Continuum Analytics(Anaconda Pythonディストリビューションのメーカー)がこの回答を気に入ったようです。これは、condaツールによって作成された仮想環境をアクティブ化するために使用される「アクティブ化」スクリプトに実装されています(参照はここにリンクされています)。いい…
wjv 14

1
これは(他にないため)ディレクトリに対してのみ機能し、「..」および「。」に対応できません。すべてを処理する必要がある私の回答をご覧ください:stackoverflow.com/a/23002317/2709
Alexander Klimetschek

3
@marbu realpathはUbuntu 14.04またはDebian Wheezyには存在しません。それはやがて標準になるかもしれませんが、確かに今ではありません。また、OPがLinuxやGNUについて何も述べていないことにも注意してください。Bashはそれよりも広く使用されています。
mc0e 2014年

76
$ readlink -m FILE
/path/to/FILE

これはより優れているreadlink -e FILEか、realpathそれはファイルが存在しない場合でも動作しますので、。


いいね。これは、存在するがシンボリックリンクではないファイル/ディレクトリでも機能します。
quietmint 2013

私はOS X 10.9(Mavericks)で利用可能なreadlinkを持っているので、これが間違いなくここでの最良の答えです。
Kenneth Hoste 2014年

6
@KennethHoste:-mMavericksではこのオプションは使用できません。
iconoclast 14

2
間違いなく、デフォルトのOSXインストールではありません。
Fran Marzoa

Linux(CentOS)で動作します
。realpath

65

絶対パスコンバーターシェル関数へのこの相対パス

  • ユーティリティは必要ありません(cdおよびのみpwd
  • ディレクトリとファイルで機能します
  • ハンドル...
  • dirまたはファイル名のスペースを処理します
  • ファイルまたはディレクトリが存在する必要があります
  • 指定されたパスに何も存在しない場合は何も返しません
  • 入力として絶対パスを処理します(基本的にパスを通過します)

コード:

function abspath() {
    # generate absolute path from relative path
    # $1     : relative filename
    # return : absolute path
    if [ -d "$1" ]; then
        # dir
        (cd "$1"; pwd)
    elif [ -f "$1" ]; then
        # file
        if [[ $1 = /* ]]; then
            echo "$1"
        elif [[ $1 == */* ]]; then
            echo "$(cd "${1%/*}"; pwd)/${1##*/}"
        else
            echo "$(pwd)/$1"
        fi
    fi
}

サンプル:

# assume inside /parent/cur
abspath file.txt        => /parent/cur/file.txt
abspath .               => /parent/cur
abspath ..              => /parent
abspath ../dir/file.txt => /parent/dir/file.txt
abspath ../dir/../dir   => /parent/dir          # anything cd can handle
abspath doesnotexist    =>                      # empty result if file/dir does not exist
abspath /file.txt       => /file.txt            # handle absolute path input

注:これはnolan6000およびbsingh からの回答に基づいていますが、ファイルの大文字と小文字を修正しています。

また、元の質問が既存のコマンドラインユーティリティに関するものであったことも理解しています。しかし、これは最小の依存関係を必要とするシェルスクリプトを含むスタックオーバーフローの問題のようですので、このスクリプトソリューションをここに置いたので、後で見つけることができます:)


ありがとう。それは私がOSXで行くものです
グレッグ

これは、スペースのあるディレクトリでは機能しません。$ abspath 'a b c/file.txt'つまり、これは、への引数cdが引用されていないためです。これを克服するには、引数全体を引用する代わりにecho(これらの引用の理由はありますか?)パス引数のみを引用します。すなわち置き換えるecho "$(cd ${1%/*}; pwd)/${1##*/}"echo $(cd "${1%/*}"; pwd)/${1##*/}
ジョージ14

@georgeご指摘ありがとうございます。修正しました。
Alexander Klimetschek 14

1
私は何十ものハーフコックソリューションを調べましたが、これは間違いなく最も簡潔で正確なbashのみのソリューションのようです。あなたはそれがさらに置換することにより、スリムな可能性echo "$(cd "$1"; pwd)"(cd "$1"; pwd)。ここではエコーの必要はありません。
2015年

@シックストゥルー、更新。中かっこ( ... )はまだ必要なので、のcd呼び出し元の作業ディレクトリを変更したくないので、サブシェルで発生しabspathます。
Alexander Klimetschek 2015年

24

findコマンドが役立つこと

find $PWD -name ex*
find $PWD -name example.log

現在のディレクトリ内またはその下にある、パターンに一致する名前のすべてのファイルを一覧表示します。少数の結果しか得られない場合(たとえば、ツリーの一番下のディレクトリにいくつかのファイルが含まれている場合)は、単純化できます。

find $PWD

私はこれを他のユーティリティが記載されていないSolaris 10で使用します。


1
私は最初の読みでこのコメントを理解しませんでした。ここで重要なのは、findコマンドに絶対パスを指定すると、結果が絶対パスで出力されることです。したがって、$ PWDの使用は現在の場所の絶対パスであり、出力は絶対パスで取得されます。
simbo1905 2013年

4
に依存しているPWD場合は、単に使用できます$PWD/$filename
jonny 2014

このアプローチは、-maxdepth 1を使用することで改善できます。また、引用を忘れないでください。これをどのように使用するかによって、ここで潜在的なセキュリティ問題が発生します。
mc0e 2014年

1
@jonny:$ filenameがすでに絶対である場合、$ PWD / $ filenameは失敗します。
mc0e 2014年

これは、ファイル名が "./filename.txt"(先頭にドットとスラッシュを含む)として指定されている場合は失敗します。
Mark Stosberg、2015

15

readlinkまたはrealpathユーティリティがない場合は、bashおよびzshで機能する次の関数を使用できます(残りについては不明)。

abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; esac; }

これは、存在しないファイルに対しても機能します(Python関数と同様os.path.abspath)。

残念ながらabspath ./../somefileドットは取り除かれません。


1
私には移植可能に見えます。一方、たとえば、改行を含むファイル名で壊れます。
Roman Cheplyaka

1
さらに向上させるためには、交換するecho "$1"printf "%s\n" "$1"(第2のエコーと同じ)。echo引数内のバックスラッシュを解釈する場合があります。
Roman Cheplyaka

再び、あなたは正しいです!実際、zshでのechoコマンドの動作はbashとは異なります。
hluk

1
厳密に言うと、POSIXでは、引数にバックスラッシュが含まれている場合、echoの動作は未定義です。ただし、XSI拡張で定義されています(つまり、echoはエスケープシーケンスを解釈する必要があります)。しかし、bashとzshはどちらもPOSIX準拠からは程遠い...
Roman Cheplyaka

申し訳ありませんが、要点はわかりません。私はすでに、これよりも多くの機能を備えたスクリプトとして回答を提供しており、シェルスクリプト内で使用する必要はありません。
dhardy

10

これは、私がそのコンパクトさのために好きなzsh専用の関数です。「A」展開修飾子を使用します— zshexpn(1)を参照してください。

realpath() { for f in "$@"; do echo ${f}(:A); done }

うわーそれはエレガントな解決策です!!
ShellFish 14

6

以下のようなもの、一般的に存在しないファイルへの(したがって、定冠詞の使用は、一般的に複数のがあるかもしれないことをこの文は、手段は適切ではありませんが)。「/」ルートから始まるすべてのパスで、独立して作業ディレクトリの曖昧させずに、ファイルを指定します。(例を参照ウィキペディア)。 absolute pathabsolute path

A relative pathは、別のディレクトリから開始して解釈されるパスです。relative pathアプリケーションで操作されている場合は(必ずしもそうではありませんが)、作業ディレクトリである可能性があります。ディレクトリ内のシンボリックリンクにある場合、通常はそのディレクトリを基準とすることを目的としています(ただし、ユーザーが他の用途を想定している場合もあります)。

したがって、絶対パスはルートディレクトリからの相対パスにすぎません。

パス(絶対パスまたは相対パス)には、シンボリックリンクが含まれる場合と含まれない場合があります。そうでない場合は、リンク構造の変更にも影響を受けませんが、これは必ずしも必要ではなく、望ましいことでもありません。一部の人々は、すべてのシンボリックリンクが解決された、つまり、リンク先のパスに置き換えられたをcanonical path(またはcanonical file nameまたはresolved path)と呼びabsolute pathます。コマンドrealpathreadlinkどちらも正規パスを検索しrealpathますが、シンボリックリンクを解決する手間をかけずに絶対パスを取得するオプションしかありません(絶対パスまたは特定のディレクトリに対する相対パスなど、さまざまな種類のパスを取得する他のオプションもいくつかあります)。

これにはいくつかの注意が必要です:

  1. シンボリックリンクは、リンクするはずのものがすでに作成されている場合にのみ解決できます。これは、常にそうであるとは限りません。コマンドrealpathreadlinkそのためのオプションがあります。
  2. パス上のディレクトリは、後でシンボリックリンクになる可能性がありcanonicalます。つまり、パスは存在しなくなります。したがって、概念は時間(または環境)に依存します。
  3. 理想的な場合でも、すべてのシンボリックリンクを解決できる場合はcanonical path、次の2つの理由により、ファイルに複数のリンクが存在する可能性があります。
    • ファイルを含むパーティションがro複数のマウントポイントに同時にマウントされた可能性があります()。
    • ファイルへのハードリンクがある可能性があります。つまり、基本的にファイルはいくつかの異なるディレクトリに存在します。

したがって、のはるかに限定的な定義を使用canonical pathしても、ファイルへの正規のパスがいくつか存在する可能性があります。これはまたcanonical、通常は一意性の概念を意味するため、修飾子はやや不適切であることを意味します。

これにより、Bashでの別の同様の質問への回答でトピックの簡単な説明が拡張されます。

私の結論は、それrealpathはよりよく設計され、より柔軟ですreadlink。これでreadlinkカバーされていないのrealpathは、シンボリックリンクの値を返すオプションのない呼び出しだけです。


私は反対票を投じられてもかまいませんが、技術的またはサイトでの適切な実践と見なされるものに関して何かを学ぶことができるように、その理由を理解したいと思います。ええと...少なくともそれは私にメタスタックオーバーフローに登録して地元の社会学をよりよく理解するようにさせました。私はそれをお勧めします。-それでも、私の答えの不適切さについて誰かが意見を持っているなら、私は興味があります。
バブー2013年

1
(a)質問には2 + 1/2年前から有効な回答があります、(b)相対パスに対応する(単一の)絶対パスがあります(これは私が欲しかったものです)。指摘した。ところでに関するコメントrealpathVS readlinkあるいはシンボリックリンクについては、私が尋ねたものに黒字です。
dhardy 2013年

1
2番目のコメント:短い講義は、長い講義よりも非常に便利です。スタックオーバーフローは通常、特定の質問をするために使用されます。
dhardy 2013年

5
1-質問の有効な回答がどれほど長く続いたという事実は、質問が終了したことを意味するものではありません。質問は個人的な使用のみを目的としたものではありません。実際、検証済みの回答よりも多くの票を集める返信用のバッジがあります。そして、新しいツールを使用すると、「最良の」答えは時間とともに変化する可能性があります。多くの人が、ウェブ検索でアクセスした古い回答を使用しています。
バブー2013年

1
2- 相対パスに対応する(単一の)絶対パスがあると主張する。「対応する」という意味、つまり、特定の変換セットを介して元のパスから派生したパスを推測しますが、ステートメントはまだ正しくありません。ユニークな「対応する」正規パスがあります。この単語canonicalは、一連の変換に対するこの一意性を正確に指します。ただし、たとえば/ dev / cdromは、実際には/ dev / sr0へのリンクですが、完全に適切な絶対パスです。どちらも同じデバイスを指しています。私の最初の答えは関連するウェブ記事を指していた。
バブー2013年

5

dogbane 答えに来ているものを説明して:

#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"

説明:

  1. このスクリプトは、引数として相対パスを取得します "$1"
  2. 次に、そのパスのdirname部分を取得します(dirまたはfileをこのスクリプトに渡すことができます)。dirname "$1"
  3. 次にcd "$(dirname "$1")、この相対ディレクトリに移動し、pwdシェルコマンドを実行して絶対パスを取得します
  4. その後、絶対パスにベース名を追加します。$(basename "$1")
  5. 最後のステップは、私たちのようecho

2

ディレクトリの場合dirname、トリップし../て戻ります./

nolan6000の関数は、それを修正するように変更できます。

get_abs_filename() {
  # $1 : relative filename
  if [ -d "${1%/*}" ]; then
    echo "$(cd ${1%/*}; pwd)/${1##*/}"
  fi
}

1
SOへようこそ!小さな変更や備考の場合、特にこのコピーされた回答に元の回答の他の多くの情報が不足している場合は、既存の回答にコメントを追加する方が回答を追加するよりも適切な場合があります。もう少し評判を集めたら、他の人の回答にコメントを追加できます。とりあえず、ユニークで価値のある質問をするか、単独で良い答えを提供することによって、評判を集めようとします。
cfi 2014年

1
nolan6000の回答について言及しているため、投稿者dhardyは、スクリプトを探していないため、nolan6000の回答を受け入れないことをすでにコメントしていることに注意してください。厳密に言えば、あなたの答えは質問に答えません。
cfi 2014年

関数を追加し.profileてインタラクティブに使用できます。
adib 2015年

これ$1は、単純なファイル名の場合は機能しません:get_abs_filename foo->なし(またはディレクトリの<current_dir>/foo/foo場合foo)。
ivan_pozdeev 2018年

2

これは質問への回答ではありませんが、スクリプトを作成する人のために:

echo `cd "$1" 2>/dev/null&&pwd||(cd "$(dirname "$1")";pwd|sed "s|/*\$|/${1##*/}|")`

/ .. ./などを正しく処理します。OSXでも動作しているようです


2

次のスクリプトをシステムに配置しました。現在のディレクトリにあるファイルへのフルパスをすばやく取得したい場合は、bashエイリアスとして呼び出します。

#!/bin/bash
/usr/bin/find "$PWD" -maxdepth 1 -mindepth 1 -name "$1"

理由はわかりませんが、OS Xではスクリプト "$ PWD"によって呼び出されると、絶対パスに展開されます。コマンドラインでfindコマンドが呼び出されても、呼び出されません。しかし、それは私が望むことをします...楽しんでください。


$PWD常に作業ディレクトリの絶対パスがあります。また、findスラッシュは許容されないので、尋ねられたとおりの質問には答えません。あなたが望んでいることを行うためのより迅速な方法は、単純にecho "$PWD/$1"
Adam Katz

2

ビルトインのみを使用する場合の最も簡単な方法は、おそらく次のとおりです。

find `pwd` -name fileName

入力する余分な2語のみ。これは、すべてのUNIXシステムとOSXで機能します。


-maxdepth 1以前に追加-nameします(ファイルが現在のディレクトリにあると仮定します)。これがないと、pwdのサブディレクトリにあるファイルは処理されますが、他のファイルは処理されません。
Walter

確かにあなたの言う通り、質問ではファイルが現在のディレクトリにあると指定されていました。「他の人とは違う」とはどういう意味ですか?
Arj

私が意味するfindディレクトリツリーの下に外部のファイルを見つけることができませんpwd。たとえば、しようとするfind . -name ../existingFileと失敗します。
Walter Tross

結局のところ、はい、これはcwd(元の質問による)またはcwdツリーの任意の場所(元の質問ではない)のファイルの完全なパスを印刷することを前提としています。
Arj

1
#! /bin/bash

file="$@"
realpath "$file" 2>/dev/null || eval realpath $(echo $file | sed 's/ /\\ /g')

これはの欠点を補っrealpathて、シェルスクリプトに格納しますfullpath。あなたは今呼び出すことができます:

$ cd && touch a\ a && rm A 2>/dev/null 
$ fullpath "a a"
/home/user/a a
$ fullpath ~/a\ a
/home/user/a a
$ fullpath A
A: No such file or directory.

それは何を解決しますか?realpath "foo bar"-> /home/myname/foo bar。コマンドライン引数を引用する気にならなければ、それはrealpath誤りではありません。
ivan_pozdeev

同意された、それはより便利なラッパーです。
ShellFish 2018年

1

Rubyで絶対パスを取得する別の方法:

realpath() {ruby -e "require 'Pathname'; puts Pathname.new('$1').realpath.to_s";}

引数なし(現在のフォルダー)で動作し、引数として相対および絶対ファイルまたはフォルダーパスを使用します。


0

Homebrewで回答

realpath最良の答えですが、インストールしていない場合は、最初に実行しbrew install coreutilsて、たくさんの素晴らしい機能を備えたcoreutilsをインストールする必要があります。カスタム関数を作成してエクスポートするのは大変な作業であり、このような場合にエラーが発生するリスクがあります。次の2行があります。

$ brew install coreutils
$ realpath your-file-name.json 

-1

古いスレッドであることはわかっていますが、私と同じようにこれを訪れた他の人への参照のために、これを投稿しています。質問が正しく理解できれば、locate $filenameコマンドだと思います。指定されたファイルの絶対パスが表示されますが、存在する場合のみです。


4
locate名前でファイル/パスを検索するユーティリティです。それは仕事をするかもしれませんが、他の一致を見つけるかもしれなくて、updatedb最初にルートとして呼び出さなければ既存のファイルを見つけないかもしれません。
dhardy 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.