bashでファイルの絶対ディレクトリを取得するにはどうすればよいですか?


82

入力ファイルを引数として取り、それを読み取るbashスクリプトを作成しました。
このファイルには、使用される追加ファイルへの(その場所に対する)いくつかのパスが含まれています。

スクリプトを入力ファイルを含むフォルダーに移動して、さらにコマンドを実行したいと思います。

では、入力ファイルからフォルダー(およびフォルダーのみ)を取得するにはどうすればよいですか?(Linuxの場合。)


入力ファイルへのフルパスを指定していますか、それとも現在の作業ディレクトリからの相対パスのみを指定していますか?
dmh 2013

dhm:入力は相対パスを示します。絶対パスからファイル名を引いたものが必要です。
BobMcGee 2013

回答:


152

フルパスを取得するには、次を使用します。

readlink -f relative/path/to/file

ファイルのディレクトリを取得するには:

dirname relative/path/to/file

2つを組み合わせることもできます。

dirname $(readlink -f relative/path/to/file)

readlink -fお使いのシステムで利用できない場合は、これを使用できます*

function myreadlink() {
  (
  cd "$(dirname $1)"         # or  cd "${1%/*}"
  echo "$PWD/$(basename $1)" # or  echo "$PWD/${1##*/}"
  )
}

相対パスとして指定されたファイルのディレクトリに移動するだけでよい場合は、絶対パスを知る必要はありません。相対パスは完全に合法なので、次を使用するだけです。

cd $(dirname relative/path/to/file)

(スクリプトの実行中に)元のパスに戻りたい場合pushdcd、の代わりにを使用し、popd完了したらを使用します。


*一方でmyreadlink、この質問の文脈で良い十分である以上、それはいくつかの制限相対を持っているreadlink上に示唆したツール。たとえば、が異なるファイルへのリンクを正しくたどりませんbasename


17
readlink -f残念ながら、これはOSXでは機能しないことに注意してください。
エミール・シット

パス全体は必要ありません。フォルダが必要です。しかし、これは役立つのに十分です:readlink -f relatedFileLocation | xargs dirname
BobMcGee 2013

1
@EmilSit:あなたは正しいです-ネイティブに。しかし、あなたはbrew install coreutilsそれを手に入れることができます。 stackoverflow.com/a/4031502/1022967
mpettis 2016

3
およびの代わりに${1%/*}または${1##*/}を使用することはお勧めしません。最初のファイル名は単純なファイル名(正しくは)を指定すると中断し、2番目のファイル名はスラッシュで終わるディレクトリ(正確には)で終了します。dirnamebasenamedirname foo.bar.basename /foo/bar/bar
カミロマーティン

1
@ChenLevy一部の人々は、より高速にするためにそれを使用する傾向があるかもしれません(私はbasename/dirname組み込みではないと思います)、そして彼らはそれが最初は機能するのを見るでしょうが、将来のある時点で突然壊れて一見良くないようです理由。私はそれをオプションとして提案することを避けたり、それが本当に防弾の疑いではないことを否定したりします。
カミロマーティン

19

のマニュアルページを見てくださいrealpath、私はそれと次のようなものを使用します:

CONTAININGDIR = $(realpath $ {FILEPATH%/ *})

あなたがやろうとしているように聞こえることをするために。


realpathは、相対的な
dirの

ありがとう!Mac OSで私のために働いた
Dmitry Klochkov 2016年

6

これは、ファイルとフォルダーの両方で機能します。

absPath(){
    if [[ -d "$1" ]]; then
        cd "$1"
        echo "$(pwd -P)"
    else 
        cd "$(dirname "$1")"
        echo "$(pwd -P)/$(basename "$1")"
    fi
}

4
$cat abs.sh
#!/bin/bash
echo "$(cd "$(dirname "$1")"; pwd -P)"

いくつかの説明:

  1. このスクリプトは、相対パスを引数として取得します "$1"
  2. 次に、そのパスのdirname部分を取得します(このスクリプトにdirまたはfileのいずれかを渡すことができます)。dirname "$1"
  3. 次にcd "$(dirname "$1");、この相対的なディレクトリに移動します
  4. pwd -P絶対パスを取得します。-Pオプションは、シンボリックリンクを避けることができます
  5. 最後のステップは、私たちのようecho

次に、スクリプトを実行します。

abs.sh your_file.txt

1

新しいBashライブラリ製品realpath-libをGitHubで試してみてください。これは、無料で邪魔にならないようにコミュニティに提供しています。クリーンでシンプル、そして十分に文書化されているので、学ぶのは素晴らしいことです。できるよ:

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

この関数はライブラリの中核です。

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

}

これはBash4 +であり、依存関係を必要とせず、get_dirname、get_filename、get_stemname、validate_pathも提供します。


0

上記の回答の問題は、「。/my-file.txt」のように「./」で入力されたファイルにあります

(多くの)回避策:

    myfile="./somefile.txt"
    FOLDER="$(dirname $(readlink -f "${ARG}"))"
    echo ${FOLDER}

-1

私はreadlinkを使用しています-fはLinuxで動作します

そう

FULL_PATH=$(readlink -f filename)
DIR=$(dirname $FULL_PATH)

PWD=$(pwd)

cd $DIR

#<do more work>

cd $PWD

5
Bashでは大文字の変数名を使用しないでください。いつか既存の変数と衝突します...ああ、そして今日は今です:変数PWDがBashにすでに存在し、その値が実際には現在のディレクトリであることをご存知ですか?そして、より多くの引用符も使用してください。
gniourf_gniourf 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.