将相对路径转换为绝对路径?

时间:2021-08-10 21:46:36

I'm not sure if these paths are duplicates. Given the relative path, how do I determine absolute path using a shell script?

我不确定这些路径是否重复。给定相对路径,如何使用shell脚本确定绝对路径?

Example:

例子:

relative path: /x/y/../../a/b/z/../c/d

absolute path: /a/b/c/d

6 个解决方案

#1


45  

From this source comes:

从这个来源:

#!/bin/bash

# Assume parameter passed in is a relative path to a directory.
# For brevity, we won't do argument type or length checking.

ABS_PATH=`cd "$1"; pwd` # double quotes for paths that contain spaces etc...
echo "Absolute path: $ABS_PATH"

You can also do a Perl one-liner, e.g. using Cwd::abs_path

您还可以使用Perl一行程序,例如使用Cwd::abs_path。

#2


50  

The most reliable method I've come across in unix is readlink -f:

我在unix中遇到的最可靠的方法是readlink -f:

$ readlink -f /x/y/../../a/b/z/../c/d
/a/b/c/d

A couple caveats:

几个事项:

  1. This also has the side-effect of resolving all symlinks. This may or may not be desirable, but usually is.
  2. 这也有解决所有符号链接的副作用。这也许是可取的,但通常是可取的。
  3. readlink will give a blank result if you reference a non-existant directory. If you want to support non-existant paths, use readlink -m instead. Unfortunately this option doesn't exist on versions of readlink released before ~2005.
  4. 如果引用一个不存在的目录,readlink将给出一个空白的结果。如果您想支持非存在路径,请使用readlink -m。不幸的是,这个选项并不存在于2005年之前发布的readlink版本中。

#3


18  

Take a look at 'realpath'.

看一看“realpath”。

$ realpath

usage: realpath [-q] path [...]

$ realpath ../../../../../

/data/home

#4


16  

Using

# Directory
relative_dir="folder/subfolder/"
absolute_dir="$( cd "$relative_dir" && pwd )"

# File
relative_file="folder/subfolder/file"
absolute_file="$( cd "${relative_file%/*}" && pwd )"/"${relative_file##*/}"
  • ${relative_file%/*} is same result as dirname "$relative_file"
  • ${relative_file%/*}与dirname“$relative_file”相同。
  • ${relative_file##*/} is same result as basename "$relative_file"
  • ${relative_file##*/}与basename“$relative_file”相同。

Caveats: Does not resolve symbolic links (i.e. does not canonicalize path ) => May not differentiate all duplicates if you use symbolic links.

注意:如果您使用符号链接,则不能解析符号链接(即,非规范化路径)=>不能区分所有的重复。


Using realpath

Command realpath does the job. An alternative is to use readlink -e (or readlink -f). However realpath is not often installed by default. If you cannot be sure realpath or readlink is present, you can substitute it using perl (see below).

命令realpath执行任务。另一种方法是使用readlink -e(或readlink -f)。不过,默认情况下不经常安装realpath。如果您不能确定realpath或readlink是否存在,您可以使用perl来替代它(参见下面)。


Using

Steven Kramer proposes a shell alias if realpath is not available in your system:

Steven Kramer提出了一个shell别名,如果您的系统中没有realpath:

$ alias realpath="perl -MCwd -e 'print Cwd::realpath(\$ARGV[0]),qq<\n>'"
$ realpath path/folder/file
/home/user/absolute/path/folder/file

or if you prefer using directly perl:

或者,如果您喜欢直接使用perl:

$ perl -MCwd -e 'print Cwd::realpath($ARGV[0]),qq<\n>' path/folder/file
/home/user/absolute/path/folder/file

This one-line perl command uses Cwd::realpath. There are in fact three perl functions. They take a single argument and return the absolute pathname. Below details are from documentation Perl5 > Core modules > Cwd.

这一行perl命令使用Cwd::realpath。实际上有三个perl函数。他们接受一个参数,并返回绝对路径名。下面的详细信息来自于>核心模块> Cwd。

  • abs_path() uses the same algorithm as getcwd(). Symbolic links and relative-path components (. and ..) are resolved to return the canonical pathname, just like realpath.

    _path()使用与getcwd()相同的算法。符号链接和相对路径组件(。并且..)被解析为返回规范路径名,就像realpath一样。

    use Cwd 'abs_path';
    my $abs_path = abs_path($file);
    
  • realpath() is a synonym for abs_path()

    realpath()是abs_path()的同义词

    use Cwd 'realpath';
    my $abs_path = realpath($file);
    
  • fast_abs_path() is a more dangerous, but potentially faster version of abs_path()

    fast_abs_path()是一个更危险的,但可能更快的版本()

    use Cwd 'fast_abs_path';
    my $abs_path = fast_abs_path($file);
    

These functions are exported only on request => therefore use Cwd to avoid the "Undefined subroutine" error as pointed out by arielf. If you want to import all these three functions, you can use a single use Cwd line:

这些函数仅在请求=>时导出,因此使用Cwd来避免arielf指出的“未定义的子例程”错误。如果您想要导入所有这三个函数,您可以使用一个单独的Cwd行:

use Cwd qw(abs_path realpath fast_abs_path);

#5


1  

Since I've run into this many times over the years, and this time around I needed a pure bash portable version that I could use on OSX and linux, I went ahead and wrote one:

由于多年来我多次遇到这种情况,而这次我需要一个纯粹的bash便携式版本,我可以在OSX和linux上使用,我继续写了一个:

The living version lives here:

活着的版本住在这里:

https://github.com/keen99/shell-functions/tree/master/resolve_path

https://github.com/keen99/shell-functions/tree/master/resolve_path

but for the sake of SO, here's the current version (I feel it's well tested..but I'm open to feedback!)

但是为了这个目的,这里是当前版本(我觉得它已经经过了很好的测试。但我愿意接受反馈!

Might not be difficult to make it work for plain bourne shell (sh), but I didn't try...I like $FUNCNAME too much. :)

也许这并不难,但我并没有尝试……我太喜欢$FUNCNAME了。:)

#!/bin/bash

resolve_path() {
    #I'm bash only, please!
    # usage:  resolve_path <a file or directory> 
    # follows symlinks and relative paths, returns a full real path
    #
    local owd="$PWD"
    #echo "$FUNCNAME for $1" >&2
    local opath="$1"
    local npath=""
    local obase=$(basename "$opath")
    local odir=$(dirname "$opath")
    if [[ -L "$opath" ]]
    then
    #it's a link.
    #file or directory, we want to cd into it's dir
        cd $odir
    #then extract where the link points.
        npath=$(readlink "$obase")
        #have to -L BEFORE we -f, because -f includes -L :(
        if [[ -L $npath ]]
         then
        #the link points to another symlink, so go follow that.
            resolve_path "$npath"
            #and finish out early, we're done.
            return $?
            #done
        elif [[ -f $npath ]]
        #the link points to a file.
         then
            #get the dir for the new file
            nbase=$(basename $npath)
            npath=$(dirname $npath)
            cd "$npath"
            ndir=$(pwd -P)
            retval=0
            #done
        elif [[ -d $npath ]]
         then
        #the link points to a directory.
            cd "$npath"
            ndir=$(pwd -P)
            retval=0
            #done
        else
            echo "$FUNCNAME: ERROR: unknown condition inside link!!" >&2
            echo "opath [[ $opath ]]" >&2
            echo "npath [[ $npath ]]" >&2
            return 1
        fi
    else
        if ! [[ -e "$opath" ]]
         then
            echo "$FUNCNAME: $opath: No such file or directory" >&2
            return 1
            #and break early
        elif [[ -d "$opath" ]]
         then 
            cd "$opath"
            ndir=$(pwd -P)
            retval=0
            #done
        elif [[ -f "$opath" ]]
         then
            cd $odir
            ndir=$(pwd -P)
            nbase=$(basename "$opath")
            retval=0
            #done
        else
            echo "$FUNCNAME: ERROR: unknown condition outside link!!" >&2
            echo "opath [[ $opath ]]" >&2
            return 1
        fi
    fi
    #now assemble our output
    echo -n "$ndir"
    if [[ "x${nbase:=}" != "x" ]]
     then
        echo "/$nbase"
    else 
        echo
    fi
    #now return to where we were
    cd "$owd"
    return $retval
}

here's a classic example, thanks to brew:

这是一个典型的例子,感谢brew:

%% ls -l `which mvn`
lrwxr-xr-x  1 draistrick  502  29 Dec 17 10:50 /usr/local/bin/mvn@ -> ../Cellar/maven/3.2.3/bin/mvn

use this function and it will return the -real- path:

使用此函数,它将返回-真实路径:

%% cat test.sh
#!/bin/bash
. resolve_path.inc
echo
echo "relative symlinked path:"
which mvn
echo
echo "and the real path:"
resolve_path `which mvn`


%% test.sh

relative symlinked path:
/usr/local/bin/mvn

and the real path:
/usr/local/Cellar/maven/3.2.3/libexec/bin/mvn

#6


0  

May be this helps:

可能是这有助于:

$path = "~user/dir/../file" 
$resolvedPath = glob($path); #   (To resolve paths with '~')
# Since glob does not resolve relative path, we use abs_path 
$absPath      = abs_path($path);

#1


45  

From this source comes:

从这个来源:

#!/bin/bash

# Assume parameter passed in is a relative path to a directory.
# For brevity, we won't do argument type or length checking.

ABS_PATH=`cd "$1"; pwd` # double quotes for paths that contain spaces etc...
echo "Absolute path: $ABS_PATH"

You can also do a Perl one-liner, e.g. using Cwd::abs_path

您还可以使用Perl一行程序,例如使用Cwd::abs_path。

#2


50  

The most reliable method I've come across in unix is readlink -f:

我在unix中遇到的最可靠的方法是readlink -f:

$ readlink -f /x/y/../../a/b/z/../c/d
/a/b/c/d

A couple caveats:

几个事项:

  1. This also has the side-effect of resolving all symlinks. This may or may not be desirable, but usually is.
  2. 这也有解决所有符号链接的副作用。这也许是可取的,但通常是可取的。
  3. readlink will give a blank result if you reference a non-existant directory. If you want to support non-existant paths, use readlink -m instead. Unfortunately this option doesn't exist on versions of readlink released before ~2005.
  4. 如果引用一个不存在的目录,readlink将给出一个空白的结果。如果您想支持非存在路径,请使用readlink -m。不幸的是,这个选项并不存在于2005年之前发布的readlink版本中。

#3


18  

Take a look at 'realpath'.

看一看“realpath”。

$ realpath

usage: realpath [-q] path [...]

$ realpath ../../../../../

/data/home

#4


16  

Using

# Directory
relative_dir="folder/subfolder/"
absolute_dir="$( cd "$relative_dir" && pwd )"

# File
relative_file="folder/subfolder/file"
absolute_file="$( cd "${relative_file%/*}" && pwd )"/"${relative_file##*/}"
  • ${relative_file%/*} is same result as dirname "$relative_file"
  • ${relative_file%/*}与dirname“$relative_file”相同。
  • ${relative_file##*/} is same result as basename "$relative_file"
  • ${relative_file##*/}与basename“$relative_file”相同。

Caveats: Does not resolve symbolic links (i.e. does not canonicalize path ) => May not differentiate all duplicates if you use symbolic links.

注意:如果您使用符号链接,则不能解析符号链接(即,非规范化路径)=>不能区分所有的重复。


Using realpath

Command realpath does the job. An alternative is to use readlink -e (or readlink -f). However realpath is not often installed by default. If you cannot be sure realpath or readlink is present, you can substitute it using perl (see below).

命令realpath执行任务。另一种方法是使用readlink -e(或readlink -f)。不过,默认情况下不经常安装realpath。如果您不能确定realpath或readlink是否存在,您可以使用perl来替代它(参见下面)。


Using

Steven Kramer proposes a shell alias if realpath is not available in your system:

Steven Kramer提出了一个shell别名,如果您的系统中没有realpath:

$ alias realpath="perl -MCwd -e 'print Cwd::realpath(\$ARGV[0]),qq<\n>'"
$ realpath path/folder/file
/home/user/absolute/path/folder/file

or if you prefer using directly perl:

或者,如果您喜欢直接使用perl:

$ perl -MCwd -e 'print Cwd::realpath($ARGV[0]),qq<\n>' path/folder/file
/home/user/absolute/path/folder/file

This one-line perl command uses Cwd::realpath. There are in fact three perl functions. They take a single argument and return the absolute pathname. Below details are from documentation Perl5 > Core modules > Cwd.

这一行perl命令使用Cwd::realpath。实际上有三个perl函数。他们接受一个参数,并返回绝对路径名。下面的详细信息来自于>核心模块> Cwd。

  • abs_path() uses the same algorithm as getcwd(). Symbolic links and relative-path components (. and ..) are resolved to return the canonical pathname, just like realpath.

    _path()使用与getcwd()相同的算法。符号链接和相对路径组件(。并且..)被解析为返回规范路径名,就像realpath一样。

    use Cwd 'abs_path';
    my $abs_path = abs_path($file);
    
  • realpath() is a synonym for abs_path()

    realpath()是abs_path()的同义词

    use Cwd 'realpath';
    my $abs_path = realpath($file);
    
  • fast_abs_path() is a more dangerous, but potentially faster version of abs_path()

    fast_abs_path()是一个更危险的,但可能更快的版本()

    use Cwd 'fast_abs_path';
    my $abs_path = fast_abs_path($file);
    

These functions are exported only on request => therefore use Cwd to avoid the "Undefined subroutine" error as pointed out by arielf. If you want to import all these three functions, you can use a single use Cwd line:

这些函数仅在请求=>时导出,因此使用Cwd来避免arielf指出的“未定义的子例程”错误。如果您想要导入所有这三个函数,您可以使用一个单独的Cwd行:

use Cwd qw(abs_path realpath fast_abs_path);

#5


1  

Since I've run into this many times over the years, and this time around I needed a pure bash portable version that I could use on OSX and linux, I went ahead and wrote one:

由于多年来我多次遇到这种情况,而这次我需要一个纯粹的bash便携式版本,我可以在OSX和linux上使用,我继续写了一个:

The living version lives here:

活着的版本住在这里:

https://github.com/keen99/shell-functions/tree/master/resolve_path

https://github.com/keen99/shell-functions/tree/master/resolve_path

but for the sake of SO, here's the current version (I feel it's well tested..but I'm open to feedback!)

但是为了这个目的,这里是当前版本(我觉得它已经经过了很好的测试。但我愿意接受反馈!

Might not be difficult to make it work for plain bourne shell (sh), but I didn't try...I like $FUNCNAME too much. :)

也许这并不难,但我并没有尝试……我太喜欢$FUNCNAME了。:)

#!/bin/bash

resolve_path() {
    #I'm bash only, please!
    # usage:  resolve_path <a file or directory> 
    # follows symlinks and relative paths, returns a full real path
    #
    local owd="$PWD"
    #echo "$FUNCNAME for $1" >&2
    local opath="$1"
    local npath=""
    local obase=$(basename "$opath")
    local odir=$(dirname "$opath")
    if [[ -L "$opath" ]]
    then
    #it's a link.
    #file or directory, we want to cd into it's dir
        cd $odir
    #then extract where the link points.
        npath=$(readlink "$obase")
        #have to -L BEFORE we -f, because -f includes -L :(
        if [[ -L $npath ]]
         then
        #the link points to another symlink, so go follow that.
            resolve_path "$npath"
            #and finish out early, we're done.
            return $?
            #done
        elif [[ -f $npath ]]
        #the link points to a file.
         then
            #get the dir for the new file
            nbase=$(basename $npath)
            npath=$(dirname $npath)
            cd "$npath"
            ndir=$(pwd -P)
            retval=0
            #done
        elif [[ -d $npath ]]
         then
        #the link points to a directory.
            cd "$npath"
            ndir=$(pwd -P)
            retval=0
            #done
        else
            echo "$FUNCNAME: ERROR: unknown condition inside link!!" >&2
            echo "opath [[ $opath ]]" >&2
            echo "npath [[ $npath ]]" >&2
            return 1
        fi
    else
        if ! [[ -e "$opath" ]]
         then
            echo "$FUNCNAME: $opath: No such file or directory" >&2
            return 1
            #and break early
        elif [[ -d "$opath" ]]
         then 
            cd "$opath"
            ndir=$(pwd -P)
            retval=0
            #done
        elif [[ -f "$opath" ]]
         then
            cd $odir
            ndir=$(pwd -P)
            nbase=$(basename "$opath")
            retval=0
            #done
        else
            echo "$FUNCNAME: ERROR: unknown condition outside link!!" >&2
            echo "opath [[ $opath ]]" >&2
            return 1
        fi
    fi
    #now assemble our output
    echo -n "$ndir"
    if [[ "x${nbase:=}" != "x" ]]
     then
        echo "/$nbase"
    else 
        echo
    fi
    #now return to where we were
    cd "$owd"
    return $retval
}

here's a classic example, thanks to brew:

这是一个典型的例子,感谢brew:

%% ls -l `which mvn`
lrwxr-xr-x  1 draistrick  502  29 Dec 17 10:50 /usr/local/bin/mvn@ -> ../Cellar/maven/3.2.3/bin/mvn

use this function and it will return the -real- path:

使用此函数,它将返回-真实路径:

%% cat test.sh
#!/bin/bash
. resolve_path.inc
echo
echo "relative symlinked path:"
which mvn
echo
echo "and the real path:"
resolve_path `which mvn`


%% test.sh

relative symlinked path:
/usr/local/bin/mvn

and the real path:
/usr/local/Cellar/maven/3.2.3/libexec/bin/mvn

#6


0  

May be this helps:

可能是这有助于:

$path = "~user/dir/../file" 
$resolvedPath = glob($path); #   (To resolve paths with '~')
# Since glob does not resolve relative path, we use abs_path 
$absPath      = abs_path($path);