在bash中扩展可能的相对路径

时间:2011-08-19 19:39:49

标签: bash absolute-path

作为我脚本的参数,有一些文件路径。那些当然可以是相对的(或包含〜)。但是对于我编写的函数,我需要绝对的路径,但是没有解析它们的符号链接。

这有什么功能吗?

11 个答案:

答案 0 :(得分:53)

MY_PATH=$(readlink -f $YOUR_ARG)将解析"./""../"

等相对路径

同样考虑这个问题(source):

#!/bin/bash
dir_resolve()
{
cd "$1" 2>/dev/null || return $?  # cd to desired directory; if fail, quell any error messages but return exit status
echo "`pwd -P`" # output full, link-resolved path
}

# sample usage
if abs_path="`dir_resolve \"$1\"`"
then
echo "$1 resolves to $abs_path"
echo pwd: `pwd` # function forks subshell, so working directory outside function is not affected
else
echo "Could not reach $1"
fi

答案 1 :(得分:35)

http://www.linuxquestions.org/questions/programming-9/bash-script-return-full-path-and-filename-680368/page3.html有以下

function abspath {
    if [[ -d "$1" ]]
    then
        pushd "$1" >/dev/null
        pwd
        popd >/dev/null
    elif [[ -e $1 ]]
    then
        pushd "$(dirname "$1")" >/dev/null
        echo "$(pwd)/$(basename "$1")"
        popd >/dev/null
    else
        echo "$1" does not exist! >&2
        return 127
    fi
}

使用pushd / popd进入pwd有用的状态。

答案 2 :(得分:15)

简单的单行:

function abs_path {
  (cd "$(dirname '$1')" &>/dev/null && printf "%s/%s" "$PWD" "${1##*/}")
}

用法:

function do_something {
    local file=$(abs_path $1)
    printf "Absolute path to %s: %s\n" "$1" "$file"
}
do_something $HOME/path/to/some\ where

我仍在试图弄清楚如何让它完全忘记路径是否存在(因此在创建文件时也可以使用它)。

答案 3 :(得分:8)

这对我来说是OS X的诀窍:$(cd SOME_DIRECTORY 2> /dev/null && pwd -P)

它应该在任何地方工作。其他解决方案似乎太复杂了。

答案 4 :(得分:5)

在OS X上

可以使用

stat -f "%N" YOUR_PATH
在Linux上

你可能有realpath个可执行文件。如果没有,以下可能会起作用(不仅仅是链接):

readlink -c YOUR_PATH

答案 5 :(得分:2)

也许这更具可读性,不使用子shell并且不会更改当前目录:

dir_resolve() {
  local dir=`dirname "$1"`
  local file=`basename "$1"`
  pushd "$dir" &>/dev/null || return $? # On error, return error code
  echo "`pwd -P`/$file" # output full, link-resolved path with filename
  popd &> /dev/null
}

答案 6 :(得分:0)

自我编辑,我刚注意到OP说他不是在寻找已解决的符号链接:

“但是对于我编写的函数,我需要绝对的路径,但是没有解析它们的符号链接。”

所以猜测这毕竟不是他的问题。 :)

由于多年来我遇到过这么多次,这次我需要一个可以在OSX和Linux上使用的纯bash便携版本,我继续编写了一个:

活着的版本住在这里:

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

但是为了SO,这是当前的版本(我觉得它经过了很好的测试......但我愿意接受反馈!)

可能不难让普通的bourne shell(sh)工作,但我没试过......我太喜欢$ 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
}

这是一个典型的例子,感谢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

使用此功能,它将返回-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

答案 7 :(得分:0)

使用readlink -f <relative-path>,例如

export FULLPATH=`readlink -f ./`

答案 8 :(得分:0)

还有另一种方法。您可以在bash脚本中使用python嵌入来解析相对路径。

abs_path=$(python3 - <<END
from pathlib import Path
path = str(Path("$1").expanduser().resolve())
print(path)
END
)

答案 9 :(得分:0)

如果您的操作系统支持,请使用:

realpath "./some/dir"

并在变量中使用它:

some_path="$(realpath "./some/dir")"

这将拓展您的道路。在Ubuntu和CentOS上进行了测试,您的可能不可用。一些建议使用readlink,但是readlink的文档说:

注意realpath(1)是用于规范化功能的首选命令。

如果人们想知道为什么我引用我的变量,那是为了保留路径中的空格。像做realpath some path会给您两个不同的路径结果。但是realpath "some path"将返回一个。引用参数ftw:)

答案 10 :(得分:-1)

你必须独家使用bash吗?我需要这样做,并厌倦了Linux和OS X之间的差异。所以我使用PHP来快速而肮脏的解决方案。

#!/usr/bin/php <-- or wherever
<?php
{
   if($argc!=2)
      exit();
   $fname=$argv[1];
   if(!file_exists($fname))
      exit();
   echo realpath($fname)."\n";
}
?>

我知道这不是一个非常优雅的解决方案,但确实有效。

相关问题