207

相対パスを指定して絶対パスを取得するコマンドはありますか?

たとえば、$lineにdir内の各ファイルの絶対パスを含める必要があります./etc/

find ./ -type f | while read line; do
   echo $line
done
4

24 に答える 24

232

試してみてくださいrealpath

~ $ sudo apt-get install realpath  # may already be installed
~ $ realpath .bashrc
/home/username/.bashrc

シンボリックリンクの拡張を回避するには、を使用しますrealpath -s

答えは「ファイルへの絶対パスを出力するbash/fishコマンド」から来ています。

于 2013-02-15T10:15:59.447 に答える
131

coreutilsパッケージがインストールされている場合は、通常readlink -f relative_file_name、絶対パッケージを取得するために使用できます(すべてのシンボリックリンクが解決されています)

于 2010-11-14T00:46:29.820 に答える
97
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"

UPDいくつかの説明

  1. このスクリプトは、引数として相対パスを取得します"$1"
  2. 次に、そのパスのdirname部分を取得します(このスクリプトにdirまたはfileのいずれかを渡すことができます)。dirname "$1"
  3. 次に、この相対ディレクトリに移動し、シェルコマンドcd "$(dirname "$1")を実行して絶対パスを取得しますpwd
  4. その後、絶対パスにベース名を追加します。$(basename "$1")
  5. 最後のステップechoとして
于 2015-07-24T08:27:54.793 に答える
79

使用する:

find "$(pwd)"/ -type f

すべてのファイルを取得する、または

echo "$(pwd)/$line"

フルパスを表示するには(相対パスが重要な場合)

于 2010-11-13T23:34:39.050 に答える
36

その価値について、私は選ばれた答えに投票しましたが、解決策を共有したいと思いました。欠点は、Linuxのみであるということです。スタックオーバーフローが発生する前に、OSXに相当するものを見つけるために約5分を費やしました。私はそれがそこにあると確信しています。

readlink -eLinuxでは、と組み合わせて使用​​できますdirname

$(dirname $(readlink -e ../../../../etc/passwd))

収量

/etc/

次に、dirnameの姉妹を使用basenameして、ファイル名を取得します

$(basename ../../../../../passwd)

収量

passwd

それをすべてまとめてください。

F=../../../../../etc/passwd
echo "$(dirname $(readlink -e $F))/$(basename $F)"

収量

/etc/passwd

ディレクトリをターゲットにしている場合は安全で、basename何も返さず、最終的な出力で2つのスラッシュが表示されます。

于 2012-11-28T07:31:35.470 に答える
28

これが最もポータブルだと思います:

abspath() {                                               
    cd "$(dirname "$1")"
    printf "%s/%s\n" "$(pwd)" "$(basename "$1")"
    cd "$OLDPWD"
}

ただし、パスが存在しない場合は失敗します。

于 2013-12-10T16:46:01.130 に答える
17

realpathおそらく最高です

だが ...

最初の質問は最初は非常に混乱しており、例として述べたように質問との関連性はほとんどありませんでした。

選択された回答は実際に与えられた例に回答し、タイトルの質問にはまったく回答しません。最初のコマンドはその答えであり(本当にそうですか?私は疑っています)、「/」がなくても同様に実行できます。そして、2番目のコマンドが何をしているのかわかりません。

いくつかの問題が混在しています:

  • 相対パス名を絶対パス名に変更することは、それが何を意味するかにかかわらず、おそらく何もしません。(通常、などのコマンドを発行する場合は、ファイルが実際に作成される前にtouch foo/bar、パス名foo/barが存在している必要があり、場合によっては計算で使用される必要があります。

  • 特にパス上のシンボリックリンク(symlinks)のために、同じファイル(または潜在的なファイル)を示す複数の絶対パス名が存在する場合がありますが、他の理由である可能性があります(デバイスは読み取り専用として2回マウントされる場合があります)。そのようなシンボリックリンクを明示的に解決したい場合としたくない場合があります。

  • 非シンボリックリンクファイルまたは名前へのシンボリックリンクのチェーンの最後に到達します。これは、実行方法に応じて、絶対パス名を生成する場合と生成しない場合があります。そして、それを絶対パス名に解決したいかもしれません。

readlink fooオプションのないコマンドfooは、引数がシンボリックリンクであり、その回答がそのシンボリックリンクの値である場合にのみ回答を提供します。他のリンクはたどられません。答えは相対パスかもしれません:シンボリックリンク引数の値が何であれ。

ただし、readlinkすべてのファイルで機能するオプション(-f -eまたは-m)があり、引数で実際に示されているファイルに1つの絶対パス名(シンボリックリンクのないパス名)を指定します。

これは、シンボリックリンクではないものには問題なく機能しますが、パス上の中間シンボリックリンクを解決せずに絶対パス名を使用したい場合があります。これはコマンドによって行われますrealpath -s foo

シンボリックリンク引数の場合、readlinkそのオプションを使用すると、引数への絶対パス上のすべてのシンボリックリンクが再び解決されますが、引数値に従うことで検出される可能性のあるすべてのシンボリックリンクも含まれます。引数のシンボリックリンク自体への絶対パスが必要な場合は、リンク先のパスではなく、それを望まない場合があります。繰り返しますfooが、がシンボリックリンクの場合realpath -s foo、引数として指定されたものを含め、シンボリックリンクを解決せずに絶対パスを取得します。

-sオプションがない場合は、リンクの値を読み取るだけでなく、他のいくつかのことを除いて、realpathとほとんど同じ です。readlinkなぜreadlinkそのオプションがあるのか​​は私にはわかりませんが、明らかに望ましくない冗長性を作成します realpath

システム間でいくつかのバリエーションがあるかもしれないことを除いて、ウェブを探索することはそれほど多くを語りません。

結論:realpath少なくともここで要求された使用法では、最も柔軟性があり、使用するのに最適なコマンドです。

于 2013-05-17T17:24:25.810 に答える
14

私のお気に入りのソリューションは @ EugenKonkovによるものでした。これは、他のユーティリティ(coreutilsパッケージ)の存在を意味するものではなかったためです。

しかし、相対パス「。」では失敗しました。および「..」なので、これらの特殊なケースを処理するわずかに改善されたバージョンがあります。

cdただし、ユーザーが相対パスの親ディレクトリにアクセスする権限を持っていない場合でも失敗します。

#! /bin/sh

# Takes a path argument and returns it as an absolute path. 
# No-op if the path is already absolute.
function to-abs-path {
    local target="$1"

    if [ "$target" == "." ]; then
        echo "$(pwd)"
    elif [ "$target" == ".." ]; then
        echo "$(dirname "$(pwd)")"
    else
        echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
    fi
}
于 2018-07-10T11:38:10.693 に答える
9

ユーゲンの答えは私にはうまくいきませんでしたが、これはうまくいきました:

    absolute="$(cd $(dirname \"$file\"); pwd)/$(basename \"$file\")"

ちなみに、現在の作業ディレクトリは影響を受けません。

于 2017-02-13T20:45:43.017 に答える
4

最良の解決策であるimhoは、https ://stackoverflow.com/a/3373298/9724628に投稿されたものです。

動作するにはPythonが必要ですが、すべてまたはほとんどのエッジケースをカバーし、非常にポータブルなソリューションのようです。

  1. シンボリックリンクを解決する場合:
python -c "import os,sys; print(os.path.realpath(sys.argv[1]))" path/to/file
  1. またはそれなし:
python -c "import os,sys; print(os.path.abspath(sys.argv[1]))" path/to/file
于 2019-02-17T23:21:18.073 に答える
4

@ernest-aのかなり素晴らしいバージョンの改善:

absolute_path() {
    cd "$(dirname "$1")"
    case $(basename $1) in
        ..) echo "$(dirname $(pwd))";;
        .)  echo "$(pwd)";;
        *)  echo "$(pwd)/$(basename $1)";;
    esac
}

これは、パスの最後の要素がである場合を正しく処理します。..この場合、"$(pwd)/$(basename "$1")"@ernest-aの答えはとして渡されaccurate_sub_path/spurious_subdirectory/..ます。

于 2019-12-27T01:04:00.573 に答える
3

の場合、find検索するための絶対パスを指定するのがおそらく最も簡単です。例:

find /etc
find `pwd`/subdir_of_current_dir/ -type f
于 2010-11-13T23:33:04.950 に答える
3

リアルパスが存在せず、そのreadlinkが絶対パスを印刷できないMac OS Xでbashを使用している場合は、独自のバージョンをコーディングして印刷するしかありません。これが私の実装です:

(純粋なbash)

abspath(){
  local thePath
  if [[ ! "$1" =~ ^/ ]];then
    thePath="$PWD/$1"
  else
    thePath="$1"
  fi
  echo "$thePath"|(
  IFS=/
  read -a parr
  declare -a outp
  for i in "${parr[@]}";do
    case "$i" in
    ''|.) continue ;;
    ..)
      len=${#outp[@]}
      if ((len==0));then
        continue
      else
        unset outp[$((len-1))] 
      fi
      ;;
    *)
      len=${#outp[@]}
      outp[$len]="$i"
      ;;
    esac
  done
  echo /"${outp[*]}"
)
}

(gawkを使用)

abspath_gawk() {
    if [[ -n "$1" ]];then
        echo $1|gawk '{
            if(substr($0,1,1) != "/"){
                path = ENVIRON["PWD"]"/"$0
            } else path = $0
            split(path, a, "/")
            n = asorti(a, b,"@ind_num_asc")
            for(i in a){
                if(a[i]=="" || a[i]=="."){
                    delete a[i]
                }
            }
            n = asorti(a, b, "@ind_num_asc")
            m = 0
            while(m!=n){
                m = n
                for(i=1;i<=n;i++){
                    if(a[b[i]]==".."){
                        if(b[i-1] in a){
                            delete a[b[i-1]]
                            delete a[b[i]]
                            n = asorti(a, b, "@ind_num_asc")
                            break
                        } else exit 1
                    }
                }
            }
            n = asorti(a, b, "@ind_num_asc")
            if(n==0){
                printf "/"
            } else {
                for(i=1;i<=n;i++){
                    printf "/"a[b[i]]
                }
            }
        }'
    fi
}

(純粋なbsd awk)

#!/usr/bin/env awk -f
function abspath(path,    i,j,n,a,b,back,out){
  if(substr(path,1,1) != "/"){
    path = ENVIRON["PWD"]"/"path
  }
  split(path, a, "/")
  n = length(a)
  for(i=1;i<=n;i++){
    if(a[i]==""||a[i]=="."){
      continue
    }
    a[++j]=a[i]
  }
  for(i=j+1;i<=n;i++){
    delete a[i]
  }
  j=0
  for(i=length(a);i>=1;i--){
    if(back==0){
      if(a[i]==".."){
        back++
        continue
      } else {
        b[++j]=a[i]
      }
    } else {
      if(a[i]==".."){
        back++
        continue
      } else {
        back--
        continue
      }
    }
  }
  if(length(b)==0){
    return "/"
  } else {
    for(i=length(b);i>=1;i--){
      out=out"/"b[i]
    }
    return out
  }
}

BEGIN{
  if(ARGC>1){
    for(k=1;k<ARGC;k++){
      print abspath(ARGV[k])
    }
    exit
  }
}
{
  print abspath($0)
}

例:

$ abspath I/am/.//..//the/./god/../of///.././war
/Users/leon/I/the/war
于 2014-02-22T07:28:09.290 に答える
2

@ ernest-aの答えに似てい$OLDPWDますが、新しい関数に影響を与えたり定義したりせずに、サブシェルを起動できます(cd <path>; pwd)

$ pwd
/etc/apache2
$ cd ../cups 
$ cd -
/etc/apache2
$ (cd ~/..; pwd)
/Users
$ cd -
/etc/cups
于 2015-05-13T09:26:41.437 に答える
2

プログラムをインストールする必要がないので、EugenKonkovの答えが最良であることがわかりました。ただし、存在しないディレクトリでは失敗します。

存在しないディレクトリで機能する関数を作成しました。

function getRealPath()
{
    local -i traversals=0
    currentDir="$1"
    basename=''
    while :; do
        [[ "$currentDir" == '.' ]] && { echo "$1"; return 1; }
        [[ $traversals -eq 0 ]] && pwd=$(cd "$currentDir" 2>&1 && pwd) && { echo "$pwd/$basename"; return 0; }
        currentBasename="$(basename "$currentDir")"
        currentDir="$(dirname "$currentDir")"
        [[ "$currentBasename" == '..' ]] && (( ++traversals )) || { [[ traversals -gt 0 ]] && (( traversals-- )) || basename="$currentBasename/$basename"; }
    done
}

成功するdirnameまでトラバースし、現在のディレクトリとによって削除されたすべてのものを返すことにより、存在しないディレクトリの問題を解決します。cddirname

于 2021-03-20T13:17:59.143 に答える
1

find $PWDまたは(bashで)を除いて、彼らが言っfind ~+たことはもう少し便利です。

于 2010-11-13T23:44:12.763 に答える
1

相対パスがディレクトリパスの場合は、私のものを試してみてください。これが最適です。

absPath=$(pushd ../SOME_RELATIVE_PATH_TO_Directory > /dev/null && pwd && popd > /dev/null)

echo $absPath
于 2015-10-13T09:37:55.770 に答える
1
echo "mydir/doc/ mydir/usoe ./mydir/usm" |  awk '{ split($0,array," "); for(i in array){ system("cd "array[i]" && echo $PWD") } }'
于 2016-03-14T20:32:28.053 に答える
1

任意の相対パス$lineにbash文字列置換を使用できます。

line=$(echo ${line/#..\//`cd ..; pwd`\/})
line=$(echo ${line/#.\//`pwd`\/})
echo $line

基本的な文字列の前部置換は、式
$ {string /#substring / replacement}に従います。これについては、 https
://www.tldp.org/LDP/abs/html/string-manipulation.htmlで詳しく説明しています。

文字は、検索/置換する文字列の一部にしたい場合に\無効にします。/

于 2020-04-30T04:46:02.400 に答える
1

Mac OS Catalina、Ubuntu 16、Centos 7の間でうまく移植できるソリューションを見つけることができなかったので、Pythonインラインでそれを行うことにしました。これは、bashスクリプトでうまく機能しました。

to_abs_path() {
  python -c "import os; print os.path.abspath('$1')"
}

to_abs_path "/some_path/../secrets"
于 2020-07-04T10:47:18.527 に答える
1

readlinkこれは、POSIXシェルとセマンティクスのみを使用して、任意の入力パスを完全に絶対化および正規化するために使用できるかなり短い関数です。

canonicalize_path() {
    (
        FILEPATH="$1"
        for _ in 1 2 3 4 5 6 7 8;  # Maximum symlink recursion depth
        do
            cd -L "`case "${FILEPATH}" in */*) echo "${FILEPATH%/*}";; *) echo ".";; esac`/"  # cd $(dirname)
            if ! FILEPATH="$(readlink "${FILEPATH##*/}" || ( echo "${FILEPATH##*/}" && false ) )";
            then
                break
            fi
        done
        cd -P "." || return $?
        echo "$(pwd)/${FILEPATH}"
    )
}

参照ファイルが存在しない場合は、最終ファイル名に至るまでのディレクトリパスのみが解決されます。ファイルパスにつながるディレクトリのいずれかが存在しない場合、cdエラーが返されます。readlink -fこれは、模倣しようとするGNU/Linuxコマンドの正確なセマンティクスです。

{1..8}bash / zshでは、数値のリストをちょうどまたは類似のものに圧縮することもできます。Linuxでは、バージョン4.2でパス全体の合計解像度が40に変更される前の長年の上限であったため、8の数が選択されました。解像度の制限に達した場合、コードは失敗しませんが、代わりに最後に考慮されたパスを返します–[ -L "${FILEPATH}" ]ただし、この状態を検出するために明示的なチェックを追加できます。

このコードは、関数とサブシェルラッパーを削除するだけで、現在の作業ディレクトリがファイルシステム内の実行されたスクリプトの場所(シェルスクリプトの一般的な要件)と一致することを確認するために簡単に再利用することもできます。

FILEPATH="$0"
for _ in 1 2 3 4 5 6 7 8;  # Maximum symlink recursion depth
do
    cd -L "`case "${FILEPATH}" in */*) echo "${FILEPATH%/*}";; *) echo ".";; esac`/"  # cd $(dirname)
    if ! FILEPATH="$(readlink "${FILEPATH##*/}" || ( echo "${FILEPATH##*/}" && false ) )";
    then
        break
    fi
done
cd -P "."
FILEPATH="$(pwd)/${FILEPATH}"
于 2020-10-21T15:46:21.717 に答える
0

相対パスを含む変数を絶対パスに変換する場合、これは機能します。

   dir=`cd "$dir"`

ここではサブシェルで実行されるため、「cd」は作業ディレクトリを変更せずにエコーします。

于 2016-08-25T05:21:42.133 に答える
0

これは他のすべてからの連鎖ソリューションです。たとえば、realpathインストールされていないか、エラーコードで終了したために失敗した場合、パスが正しくなるまで次のソリューションが試行されます。

#!/bin/bash

function getabsolutepath() {
    local target;
    local changedir;
    local basedir;
    local firstattempt;

    target="${1}";
    if [ "$target" == "." ];
    then
        printf "%s" "$(pwd)";

    elif [ "$target" == ".." ];
    then
        printf "%s" "$(dirname "$(pwd)")";

    else
        changedir="$(dirname "${target}")" && basedir="$(basename "${target}")" && firstattempt="$(cd "${changedir}" && pwd)" && printf "%s/%s" "${firstattempt}" "${basedir}" && return 0;
        firstattempt="$(readlink -f "${target}")" && printf "%s" "${firstattempt}" && return 0;
        firstattempt="$(realpath "${target}")" && printf "%s" "${firstattempt}" && return 0;

        # If everything fails... TRHOW PYTHON ON IT!!!
        local fullpath;
        local pythoninterpreter;
        local pythonexecutables;
        local pythonlocations;

        pythoninterpreter="python";
        declare -a pythonlocations=("/usr/bin" "/bin");
        declare -a pythonexecutables=("python" "python2" "python3");

        for path in "${pythonlocations[@]}";
        do
            for executable in "${pythonexecutables[@]}";
            do
                fullpath="${path}/${executable}";

                if [[ -f "${fullpath}" ]];
                then
                    # printf "Found ${fullpath}\\n";
                    pythoninterpreter="${fullpath}";
                    break;
                fi;
            done;

            if [[ "${pythoninterpreter}" != "python" ]];
            then
                # printf "Breaking... ${pythoninterpreter}\\n"
                break;
            fi;
        done;

        firstattempt="$(${pythoninterpreter} -c "import os, sys; print( os.path.abspath( sys.argv[1] ) );" "${target}")" && printf "%s" "${firstattempt}" && return 0;
        # printf "Error: Could not determine the absolute path!\\n";
        return 1;
    fi
}

printf "\\nResults:\\n%s\\nExit: %s\\n" "$(getabsolutepath "./asdfasdf/ asdfasdf")" "${?}"
于 2019-07-05T04:23:47.340 に答える
0

@EugenKonkovによるこの回答@HashChangeによるこの回答に基づいて、私の回答は前者の簡潔さと後者の処理を組み合わせたものです。以下のすべてのオプションは、基本的なシェルコマンド言語POSIX標準にのみ依存していると思います。...

dirnameおよびを使用basenameする場合のオプションは次のとおりです。

absPathDirname()
{
    [ -d "${1}" ] && set -- "${1}" || set -- "`dirname "${1}"`" "/`basename "${1}"`"
    echo "`cd "${1}"; pwd`${2}";
}

dirnameまたはを使用しないbasename場合の別の簡単なオプションは次のとおりです。

absPathMinusD()
{
    [ -d "${1}" ] && set -- "${1}" || set -- "${1%${1##*/}}" "/${1##*/}"
    echo "`cd "${1:-.}"; pwd`${2}";
}

上記の2つのオプションのいずれかをお勧めします。残りは楽しみのためだけです...

Grepバージョン:

absPathGrep()
{
    echo "`[ "${1##/*}" ] && echo "$1" | grep -Eo '^(.*/)?\.\.($|/)' | { read d && cd "$d"; echo "${PWD}/${1#$d}"; } || echo "$1"`"
}

「シェルの制限された正規表現で何ができるか」の興味深い例として:

absPathShellReplace()
{
    E="${1##*/}"; D="${E#$E${E#.}}"; DD="${D#$D${D#..}}"
    DIR="${1%$E}${E#$DD}"; FILE="${1#$DIR}"; SEP=${FILE:+/}
    echo "`cd "${DIR:-.}"; pwd`${SEP#$DIR}$FILE"
}
于 2021-05-03T13:22:42.057 に答える