web-dev-qa-db-fra.com

Développer un chemin relatif possible dans bash

Comme arguments de mon script, il y a des chemins de fichiers. Celles-ci peuvent bien sûr être relatives (ou contenir ~). Mais pour les fonctions que j'ai écrites, j'ai besoin de chemins absolus, mais leurs liens symboliques ne sont pas résolus.

Y at-il une fonction pour cela?

56
laar

MY_PATH=$(readlink -f $YOUR_ARG) résoudra les chemins relatifs tels que "./" et "../"

Considérez ceci également ( 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
53
Amir Afghani

http://www.linuxquestions.org/questions/programming-9/bash-script-return-full-path-and-filename-680368/page3.html présente les éléments suivants

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
}

qui utilise pushd/popd pour entrer dans un état où pwd est utile.

34
Mike Samuel

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

J'essaie toujours de comprendre comment je peux le faire complètement oublier que le chemin existe ou non (afin qu'il puisse également être utilisé lors de la création de fichiers).

14
andsens

Cela me convient sous OS X: $(cd SOME_DIRECTORY 2> /dev/null && pwd -P)

Cela devrait fonctionner n'importe où. Les autres solutions semblaient trop compliquées.

7
Mike Pulaski

sur OS X, vous pouvez utiliser

stat -f "%N" YOUR_PATH

sur linux, vous aurez peut-être realpath exécutable. sinon, ce qui suit pourrait fonctionner (pas seulement pour les liens):

readlink -c YOUR_PATH
5
Vitaly Kushner

Peut-être que ceci est plus lisible et n'utilise pas de sous-shell et ne change pas le répertoire actuel:

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
}
1
sja

Utilisez readlink -f <relative-path>, par exemple.

export FULLPATH=`readlink -f ./`
0
isapir

Il y a une autre méthode. Vous pouvez utiliser python imbriqué dans un script bash pour résoudre un chemin relatif.

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

moi-même, j'ai juste remarqué que l'OP disait qu'il ne cherchait pas les liens symboliques résolus:

"Mais pour les fonctions que j'ai écrites, j'ai besoin de chemins absolus, mais leurs liens symboliques ne sont pas résolus."

Donc, suppose que ce n’est pas si approprié à sa question après tout. :)

Depuis que je suis confronté à cela de nombreuses fois au fil des ans, et cette fois-ci, j'avais besoin d'une version portable pur bash que je pouvais utiliser sur OSX et Linux, je me suis lancé et j'en ai écrit une:

La version vivante vit ici:

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

mais dans l’intérêt de SO, voici la version actuelle (j’estime qu’elle est bien testée, mais je suis ouvert aux commentaires!)

Ce n’est peut-être pas difficile de le faire fonctionner pour Plain Bourne Shell (sh), mais je n’ai pas essayé ... J'aime trop $ 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
}

voici un exemple classique, grâce à brasser:

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

utilisez cette fonction et elle retournera le chemin -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
0
keen