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

发布于 2024-11-30 18:07:56 字数 94 浏览 2 评论 0原文

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

有没有这方面的功能?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

浅语花开 2024-12-07 18:07:56

MY_PATH=$(readlink -f $YOUR_ARG) 将解析相对路径,如 "./""../"

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

#!/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

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

Consider this as well (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
小糖芽 2024-12-07 18:07:56

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 有用的状态。

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

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
}

which uses pushd/popd to get into a state where pwd is useful.

陌上青苔 2024-12-07 18:07:56

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

realpath -s "./some/dir"

并在变量中使用它:

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

这将扩展您的路径。在 Ubuntu 和 CentOS 上进行了测试,可能不适用于您的系统。有些人推荐 readlink,但 readlink 的文档说:

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

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

感谢 NyanPasu64 的提醒。如果您不希望它遵循符号链接,则需要添加 -s

If your OS supports it, use:

realpath -s "./some/dir"

And using it in a variable:

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

Which will expand your path. Tested on Ubuntu and CentOS, might not be available on yours. Some recommend readlink, but documentation for readlink says:

Note realpath(1) is the preferred command to use for canonicalization functionality.

In case people wonder why I quote my variables, it's to preserve spaces in paths. Like doing realpath some path will give you two different path results. But realpath "some path" will return one. Quoted parameters ftw :)

Thanks to NyanPasu64 for the heads up. You'll want to add -s if you don't want it to follow the symlinks.

雨的味道风的声音 2024-12-07 18:07:56

简单的一句:

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

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

Simple one-liner:

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

Usage:

function do_something {
    local file=$(abs_path $1)
    printf "Absolute path to %s: %s\n" "$1" "$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).

葬心 2024-12-07 18:07:56

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

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

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

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

逆流 2024-12-07 18:07:56

使用 readlink -f,例如

export FULLPATH=`readlink -f ./`

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

export FULLPATH=`readlink -f ./`
乱了心跳 2024-12-07 18:07:56

也许这更具可读性,并且不使用子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
}

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

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
}
旧梦荧光笔 2024-12-07 18:07:56

在 OS X 上,您可以

stat -f "%N" YOUR_PATH

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

readlink -c YOUR_PATH

on OS X you can use

stat -f "%N" YOUR_PATH

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

readlink -c YOUR_PATH
巷雨优美回忆 2024-12-07 18:07:56

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

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

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

abs_path=$(python3 - <<END
from pathlib import Path
path = str(Path("$1").expanduser().resolve())
print(path)
END
)
惯饮孤独 2024-12-07 18:07:56

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

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

所以我猜这毕竟不太适合他的问题。 :)

因为这些年来我已经多次遇到这个问题,而这一次我需要一个可以在 OSX 和 Linux 上使用的纯 bash 便携式版本,所以我继续写了一个:

实时版本在这里:

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

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

使其适用于普通的 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-路径:

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

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

"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:

The living version lives here:

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. :)

#!/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:

%% 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
梦途 2024-12-07 18:07:56

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

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

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.

#!/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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文