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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7126580/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 05:47:12  来源:igfitidea点击:

Expand a possible relative path in bash

linuxbashabsolute-path

提问by laar

As arguments to my script there are some file paths. Those can, of course, be relative (or contain ~). But for the functions I've written I need paths that are absolute, but do not have their symlinks resolved.

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

Is there any function for this?

有什么功能吗?

回答by Amir Afghani

MY_PATH=$(readlink -f $YOUR_ARG)will resolve relative paths like "./"and "../"

MY_PATH=$(readlink -f $YOUR_ARG)将解析像"./"和这样的相对路径"../"

Consider this as well (source):

也请考虑这一点(来源):

#!/bin/bash
dir_resolve()
{
cd "" 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 \"\"`"
then
echo " resolves to $abs_path"
echo pwd: `pwd` # function forks subshell, so working directory outside function is not affected
else
echo "Could not reach "
fi

回答by Mike Samuel

http://www.linuxquestions.org/questions/programming-9/bash-script-return-full-path-and-filename-680368/page3.htmlhas the following

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

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

which uses pushd/popdto get into a state where pwdis useful.

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

回答by Vitaly Kushner

on OS X you can use

在 OS X 上你可以使用

stat -f "%N" YOUR_PATH

on linux you might have realpathexecutable. if not, the following might work (not only for links):

在 linux 上,您可能有realpath可执行文件。如果没有,以下可能有效(不仅适用于链接):

readlink -c YOUR_PATH

回答by David G

Do you have to use bash exclusively? I needed to do this and got fed up with differences between Linux and OS X. So I used PHP for a quick and dirty solution.

你必须只使用 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";
}
?>

I know it's not a very elegant solution but it does work.

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

回答by andsens

Simple one-liner:

简单的单线:

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

Usage:

用法:

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

I am still trying to figure out how I can get it to be completely oblivious to whether the path exists or not (so it can be used when creating files as well).

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

回答by sja

Maybe this is more readable and does not use a subshell and does not change the current dir:

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

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

回答by keen

self edit, I just noticed the OP said he's not looking for symlinks resolved:

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

"But for the functions I've written I need paths that are absolute, but do not have their symlinks resolved."

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

So guess this isn't so apropos to his question after all. :)

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

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:

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

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!)

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

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

让它适用于普通的 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 " >&2
    local opath=""
    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:

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

%% 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

回答by Mikey

This does the trick for me on OS X: $(cd SOME_DIRECTORY 2> /dev/null && pwd -P)

这在 OS X 上对我有用: $(cd SOME_DIRECTORY 2> /dev/null && pwd -P)

It should work anywhere. The other solutions seemed too complicated.

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

回答by isapir

Use readlink -f <relative-path>, e.g.

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

export FULLPATH=`readlink -f ./`

回答by cy8g3n

There's another method. You can use python embedding in bash script to resolve a relative path.

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

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