Преобразование относительного пути в абсолютный путь?

StackOverflow https://stackoverflow.com/questions/4045253

Вопрос

Я не уверен, что эти пути дубликаты. Учитывая относительный путь, как я могу определить абсолютный путь, используя сценарий оболочки?

Пример:

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

absolute path: /a/b/c/d
Это было полезно?

Решение

От Это источник Приходит:

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

Вы также можете сделать один-лайнер Perl, например, используя Cwd::abs_path

Другие советы

Самый надежный метод, который я сталкивался в Unix, readlink -f:

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

Пара предупреждает:

  1. Это также имеет побочный эффект разрешения всех симLinks. Это может или не может быть желательно, но обычно есть.
  2. readlink даст пустое результат, если вы ссылаетесь на несуществующий каталог. Если вы хотите поддержать несуществующие пути, используйте readlink -m вместо. К сожалению, эта опция не существует на версиях ReadLink, выпущенной до ~ 2005 года.

С использованием

# 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%/*} такой же результат, как dirname "$relative_file"
  • ${relative_file##*/} такой же результат, как basename "$relative_file"

Оговорки: Не разрешает символические ссылки (т. Е. Не каницируют путь) => Не может различать все дубликаты, если вы используете символические ссылки.


С использованием realpath

Команда realpath делает работу. Альтернатива - использовать readlink -e (или readlink -f). Однако realpath не часто устанавливается по умолчанию. Если вы не можете быть уверены realpath или readlink Присутствует, вы можете заменить его, используя Perl (см. Ниже).


С использованием

Стивен Крамер Предлагает псевдоним оболочки, если realpath не доступен в вашей системе:

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

Или если вы предпочитаете использовать напрямую Perl:

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

Эта команда One-Line Perl использует Cwd::realpath. Отказ Существуют на самом деле три функции Perl. Они берут один аргумент и вернут абсолютный путь. Ниже подробности из документации Perl5> Основные модули> CWD.

  • abs_path() использует тот же алгоритм, что и getcwd(). Отказ Символические ссылки и компоненты относительного пути (. а также ..) разрешены для возврата канонического пути, как realpath.

    use Cwd 'abs_path';
    my $abs_path = abs_path($file);
    
  • realpath() это синоним для abs_path()

    use Cwd 'realpath';
    my $abs_path = realpath($file);
    
  • fast_abs_path() является более опасным, но потенциально быстрее версия abs_path()

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

Эти функции экспортируются только по запросу => поэтому использовать Cwd чтобы избежать «Неопределенный подпрограмм» Ошибка, как указано arielf.. Отказ Если вы хотите импортировать все эти три функции, вы можете использовать один use Cwd линия:

use Cwd qw(abs_path realpath fast_abs_path);

Посмотрите на «RealPath».

$ realpath

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

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

/data/home

Поскольку я пробежал в это много раз за эти годы, и на этот раз мне нужна была чистая портативная версия Bash, которую я мог бы использовать на OSX и Linux, я пошел вперед и написал один:

Живая версия живет здесь:

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

Но ради этого, вот текущая версия (я чувствую, что это хорошо проверено .. Но я открыт для отзывы!)

Возможно, не может быть трудно сделать его работать на простых раковины Борна (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

Может быть, это помогает:

$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);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top