web-dev-qa-db-ja.com

ファイルへの絶対パスを表示するためのbash / fishコマンド

質問:どちらのファイルを絶対パスで表示するための簡単なsh/bash/zsh/fish/...コマンドがありますか?

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

これがabspath.pyのサンプル実装です。

#!/usr/bin/python
# Author: Diggory Hardy <[email protected]>
# 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)
368
dhardy

realpathを試してください。

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

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

readlink -e /foo/bar/baz
294
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"
224
dogbane

あなたのシステムにインストールされているかもしれないしインストールされていないかもしれない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コマンドが引数なしで呼び出されたときに現在のディレクトリの絶対パスを表示するという事実を利用します。

なぜ私はこの解決策が好きですか?

移植性があり、特定のLinux/Unixディストリビューションのデフォルトインストールには存在しないことが多いreadlinkrealpathも必要ありません。

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
}
73
peterh
$ readlink -m FILE
/path/to/FILE

ファイルが存在しなくても機能するので、これはreadlink -e FILEまたはrealpathより優れています。

73
Flimm

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

  • ユーティリティを必要としません(cdpwdのみ)
  • ディレクトリとファイルで動作します
  • ...を処理します
  • ディレクトリまたはファイル名の中のスペースを処理します。
  • ファイルまたはディレクトリが存在する必要があります
  • 与えられたパスに何も存在しない場合は何も返しません
  • 絶対パスを入力として処理します(基本的にこれらを渡します)。

コード:

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

注:これは、 from nolan60 および bsingh の回答に基づいていますが、ファイルの大文字と小文字は区別されます。

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

58

findコマンドが役に立つかもしれません

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

現在のディレクトリ以下のすべてのファイルをパターンに一致する名前で一覧表示します。ほんの少しの結果しか得られない場合は単純化できます(例:ファイルが少ないツリーの一番下のディレクトリ)

find $PWD

私はSolaris 10でこれを使用していますが、他のユーティリティは言及されていません。

22
lessthanideal

もしあなたがreadlinkやrealpathユーティリティを持っていないのであれば、bashとzshで動く次の関数を使うことができます(残りについてはよくわからない)。

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

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

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

14
hluk

これが私がそのコンパクトさのために好きであるzshだけの機能です。それは 'A'拡張修飾子を使います - zshexpn(1)を見てください。

realpath() { for f in "[email protected]"; do echo ${f}(:A); done }
9
wjv

ファイルへのabsolute pathのようなものは一般的にはありません(このステートメントは、一般的に複数のものがあることを意味します。したがって、定冠詞を使用しますは適切ではありません)。 absolute pathは、ルート "/"から始まる任意のパスで、作業ディレクトリとは関係なく、あいまいさのないファイルを指定します(たとえば、 Wikipedia を参照)。

relative pathは、他のディレクトリから開始して解釈されるパスです。アプリケーションによって操作されているrelative pathの場合は、作業ディレクトリになる可能性があります(必ずしもそうとは限りません)。それがディレクトリ内のシンボリックリンクにあるとき、それは一般的にそのディレクトリに相対的であることを意図しています(ユーザは他の用途を念頭に置いているかもしれませんが)。

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

パス(絶対パスまたは相対パス)には、シンボリックリンクが含まれている場合と含まれていない場合があります。もしそうでなければ、それはまたリンク構造の変化に対して幾分不透過性であるが、これは必ずしも必要ではないかまたは望ましくさえない。 canonical path(またはcanonical file nameまたはresolved path)を、すべてのシンボリックリンクが解決された、つまりリンク先のパスに置き換えられたabsolute pathと呼ぶ人もいます。コマンドrealpathreadlinkはどちらも正規のパスを探しますが、realpathだけがシンボリックリンクを解決するために迷惑をかけずに絶対パスを取得するためのオプションを持っています。絶対パスまたは何らかのディレクトリに対する相対パス。

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

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

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

これは で他の似たような質問に対する答えの中でトピックの簡単な議論を拡張します:与えられた相対的な絶対パスを検索する

私の結論は、realpathreadlinkよりも優れて設計され、はるかに柔軟であるということです。 readlinkでカバーされていないrealpathの唯一の使用法は、シンボリックリンクの値を返すオプションなしの呼び出しです。

7
babou

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を追加します。$(basename "$1")
  5. 最後のステップとして、それをechoにします。
3
Eugen Konkov

これは質問に対する答えではありませんが、スクリプトを書く人のためのものです。

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

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

2
Alek

ディレクトリの場合、dirname../を取得して./を返します。

nolan6000の関数 はそれを修正するために修正することができます。

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

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

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

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

2
fred.johnsen
#! /bin/bash

file="[email protected]"
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.
1
ShellFish

Rubyで絶対パスを取得するための代替手段:

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

引数として引数なし(現在のフォルダ)、相対パス、絶対パス、またはフォルダパスを指定して動作します。

1
Atika