Existe-t-il une commande pour récupérer le chemin absolu étant donné le chemin relatif?
Par exemple, je veux que $ line contienne le chemin absolu de chaque fichier dans dir ./etc/
find ./ -type f | while read line; do
   echo $line
doneExiste-t-il une commande pour récupérer le chemin absolu étant donné le chemin relatif?
Par exemple, je veux que $ line contienne le chemin absolu de chaque fichier dans dir ./etc/
find ./ -type f | while read line; do
   echo $line
doneRéponses:
utilisation:
find "$(pwd)"/ -type fpour obtenir tous les fichiers ou
echo "$(pwd)/$line"pour afficher le chemin complet (si le chemin relatif est important)
$(pwd)à la place de $PWD? (oui, je sais que pwdc'est un builtin)
                    Essayez realpath.
~ $ sudo apt-get install realpath  # may already be installed
~ $ realpath .bashrc
/home/username/.bashrcPour éviter de développer les liens symboliques, utilisez realpath -s.
La réponse vient de " la commande bash / fish pour imprimer le chemin absolu vers un fichier ".
realpathne semble pas disponible sur Mac (OS X 10.11 "El Capitan"). :-(
                    realpathne semble pas non plus disponible sur CentOS 6
                    brew install coreutilsapporterarealpath
                    realpathest déjà présent. Je n'ai pas eu à l'installer séparément.
                    realpathest disponible sur Git pour Windows (pour moi, du moins).
                    Si vous avez installé le package coreutils, vous pouvez généralement l'utiliser readlink -f relative_file_namepour récupérer le package absolu (avec tous les liens symboliques résolus)
brew install coreutils. Cependant l'exécutable est précédé de ag:greadlink -f relative_file_name
                    #! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"UPD Quelques explications
"$1"dirname "$1"cd "$(dirname "$1")dans ce répertoire relatif et obtenons le chemin absolu pour celui-ci en exécutant la pwdcommande shell$(basename "$1")echonerealpathou readlink -ffaire. Par exemple, cela ne fonctionne pas sur les chemins où le dernier composant est un lien symbolique.
                    -Poption pour pwdcommander:echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"
                    Pour ce que ça vaut, j'ai voté pour la réponse choisie, mais je voulais partager une solution. L'inconvénient est qu'il ne s'agit que de Linux - j'ai passé environ 5 minutes à essayer de trouver l'équivalent OSX avant d'arriver à Stack overflow. Je suis sûr que c'est là-bas cependant.
Sous Linux, vous pouvez utiliser readlink -een tandem avec dirname.
$(dirname $(readlink -e ../../../../etc/passwd))rendements
/etc/Et puis vous utilisez dirnamela sœur de, basenamepour simplement obtenir le nom du fichier
$(basename ../../../../../passwd)rendements
passwdMets le tout ensemble..
F=../../../../../etc/passwd
echo "$(dirname $(readlink -e $F))/$(basename $F)"rendements
/etc/passwdVous êtes en sécurité si vous ciblez un répertoire, basenamene retournera rien et vous vous retrouverez simplement avec des doubles barres obliques dans la sortie finale.
dirname, readlinket basename. Cela m'a aidé à trouver le chemin absolu d'un lien symbolique - pas sa cible.
                    /home/GKFXet que je tape touch newfile, alors avant d'appuyer sur Entrée, vous pourriez comprendre que je veux dire "create / home / GKFX / newfile", qui est un chemin absolu vers un fichier qui n'existe pas encore.
                    Je pense que c'est le plus portable:
abspath() {                                               
    cd "$(dirname "$1")"
    printf "%s/%s\n" "$(pwd)" "$(basename "$1")"
    cd "$OLDPWD"
}Cela échouera si le chemin n'existe pas.
dirnamec'est un utilitaire de base GNU, pas commun à tous les Unixen je crois.
                    dirnameest un utilitaire standard POSIX, voir ici: pubs.opengroup.org/onlinepubs/9699919799/utilities/dirname.html
                    ${1##*/}depuis un jour maintenant, et maintenant que j'ai remplacé cette poubelle par basename "$1"elle semble enfin gérer correctement les chemins qui se terminent par /.
                    ../..
                    realpath est probablement le meilleur
Mais ...
La question initiale était très confuse au départ, avec un exemple mal lié à la question comme indiqué.
La réponse choisie répond en fait à l'exemple donné, et pas du tout à la question du titre. La première commande est cette réponse (est-ce vraiment? Je doute), et pourrait faire aussi bien sans le '/'. Et je ne vois pas ce que fait la deuxième commande.
Plusieurs problèmes sont mitigés:
changer un chemin relatif en chemin absolu, quoi qu'il dénote, peut-être rien. ( En règle générale, si vous exécutez une commande telle que touch foo/bar, le chemin d'accès foo/bardoit exister pour vous, et éventuellement être utilisé dans le calcul, avant que le fichier ne soit réellement créé. )
il peut y avoir plusieurs chemins absolus qui désignent le même fichier (ou fichier potentiel), notamment à cause de liens symboliques (symlinks) sur le chemin, mais éventuellement pour d'autres raisons (un périphérique peut être monté deux fois en lecture seule). On peut ou non vouloir résoudre explicitement ces liens symboliques.
arriver à la fin d'une chaîne de liens symboliques vers un fichier ou un nom sans lien symbolique. Cela peut ou non donner un nom de chemin absolu, selon la façon dont cela est fait. Et on peut, ou peut ne pas vouloir le résoudre en un chemin absolu.
La commande readlink foosans option donne une réponse uniquement si son argument fooest un lien symbolique, et cette réponse est la valeur de ce lien symbolique. Aucun autre lien n'est suivi. La réponse peut être un chemin relatif: quelle que soit la valeur de l'argument du lien symbolique.
Cependant, readlinka des options (-f -e ou -m) qui fonctionneront pour tous les fichiers, et donneront un chemin absolu (celui sans lien symbolique) au fichier réellement indiqué par l'argument.
Cela fonctionne bien pour tout ce qui n'est pas un lien symbolique, bien que l'on puisse souhaiter utiliser un chemin absolu sans résoudre les liens symboliques intermédiaires sur le chemin. Ceci est fait par la commanderealpath -s foo
Dans le cas d'un argument de lien symbolique, readlinkavec ses options résoudra à nouveau tous les liens symboliques sur le chemin absolu de l'argument, mais cela inclura également tous les liens symboliques qui peuvent être rencontrés en suivant la valeur de l'argument. Vous ne voudrez peut-être pas cela si vous souhaitez un chemin absolu vers le lien symbolique de l'argument lui-même, plutôt que vers celui auquel il peut être lié. Encore une fois, si fooest un lien symbolique, realpath -s fooobtiendra un chemin absolu sans résoudre les liens symboliques, y compris celui donné en argument.
Sans l' -soption, realpathfait à peu près la même chose que
 readlink, sauf pour simplement lire la valeur d'un lien, ainsi que plusieurs autres choses. Il n'est tout simplement pas clair pour moi pourquoi readlinka ses options, créant apparemment une redondance indésirable avec
 realpath.
Explorer le Web ne dit pas grand chose de plus, sauf qu'il peut y avoir des variations entre les systèmes.
Conclusion: realpathc'est la meilleure commande à utiliser, avec le plus de flexibilité, du moins pour l'utilisation demandée ici.
Ma solution préférée était celle de @EugenKonkov car elle n'impliquait pas la présence d'autres utilitaires (le package coreutils).
Mais il a échoué pour les chemins relatifs "." et "..", voici donc une version légèrement améliorée gérant ces cas particuliers.
cdCependant, cela échoue toujours si l'utilisateur n'a pas l'autorisation d' accéder au répertoire parent du chemin relatif.
#! /bin/sh
# Takes a path argument and returns it as an absolute path. 
# No-op if the path is already absolute.
function to-abs-path {
    local target="$1"
    if [ "$target" == "." ]; then
        echo "$(pwd)"
    elif [ "$target" == ".." ]; then
        echo "$(dirname "$(pwd)")"
    else
        echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
    fi
}La réponse d'Eugen n'a pas vraiment fonctionné pour moi, mais cela a fonctionné:
    absolute="$(cd $(dirname \"$file\"); pwd)/$(basename \"$file\")"Remarque: votre répertoire de travail actuel n'est pas affecté.
La meilleure solution, à mon humble avis, est celle publiée ici: https://stackoverflow.com/a/3373298/9724628 .
Cela nécessite python pour fonctionner, mais il semble couvrir tous ou la plupart des cas marginaux et être une solution très portable.
python -c "import os,sys; print(os.path.realpath(sys.argv[1]))" path/to/filepython -c "import os,sys; print(os.path.abspath(sys.argv[1]))" path/to/fileSi vous utilisez bash sur Mac OS X qui n'a pas de realpath et que son readlink peut imprimer le chemin absolu, vous pouvez avoir le choix de coder votre propre version pour l'imprimer. Voici ma mise en œuvre:
(pure bash)
abspath(){
  local thePath
  if [[ ! "$1" =~ ^/ ]];then
    thePath="$PWD/$1"
  else
    thePath="$1"
  fi
  echo "$thePath"|(
  IFS=/
  read -a parr
  declare -a outp
  for i in "${parr[@]}";do
    case "$i" in
    ''|.) continue ;;
    ..)
      len=${#outp[@]}
      if ((len==0));then
        continue
      else
        unset outp[$((len-1))] 
      fi
      ;;
    *)
      len=${#outp[@]}
      outp[$len]="$i"
      ;;
    esac
  done
  echo /"${outp[*]}"
)
}(utilisez gawk)
abspath_gawk() {
    if [[ -n "$1" ]];then
        echo $1|gawk '{
            if(substr($0,1,1) != "/"){
                path = ENVIRON["PWD"]"/"$0
            } else path = $0
            split(path, a, "/")
            n = asorti(a, b,"@ind_num_asc")
            for(i in a){
                if(a[i]=="" || a[i]=="."){
                    delete a[i]
                }
            }
            n = asorti(a, b, "@ind_num_asc")
            m = 0
            while(m!=n){
                m = n
                for(i=1;i<=n;i++){
                    if(a[b[i]]==".."){
                        if(b[i-1] in a){
                            delete a[b[i-1]]
                            delete a[b[i]]
                            n = asorti(a, b, "@ind_num_asc")
                            break
                        } else exit 1
                    }
                }
            }
            n = asorti(a, b, "@ind_num_asc")
            if(n==0){
                printf "/"
            } else {
                for(i=1;i<=n;i++){
                    printf "/"a[b[i]]
                }
            }
        }'
    fi
}(pure bsd awk)
#!/usr/bin/env awk -f
function abspath(path,    i,j,n,a,b,back,out){
  if(substr(path,1,1) != "/"){
    path = ENVIRON["PWD"]"/"path
  }
  split(path, a, "/")
  n = length(a)
  for(i=1;i<=n;i++){
    if(a[i]==""||a[i]=="."){
      continue
    }
    a[++j]=a[i]
  }
  for(i=j+1;i<=n;i++){
    delete a[i]
  }
  j=0
  for(i=length(a);i>=1;i--){
    if(back==0){
      if(a[i]==".."){
        back++
        continue
      } else {
        b[++j]=a[i]
      }
    } else {
      if(a[i]==".."){
        back++
        continue
      } else {
        back--
        continue
      }
    }
  }
  if(length(b)==0){
    return "/"
  } else {
    for(i=length(b);i>=1;i--){
      out=out"/"b[i]
    }
    return out
  }
}
BEGIN{
  if(ARGC>1){
    for(k=1;k<ARGC;k++){
      print abspath(ARGV[k])
    }
    exit
  }
}
{
  print abspath($0)
}exemple:
$ abspath I/am/.//..//the/./god/../of///.././war
/Users/leon/I/the/warSi le chemin relatif est un chemin de répertoire, essayez le mien, cela devrait être le meilleur:
absPath=$(pushd ../SOME_RELATIVE_PATH_TO_Directory > /dev/null && pwd && popd > /dev/null)
echo $absPathecho "mydir/doc/ mydir/usoe ./mydir/usm" |  awk '{ split($0,array," "); for(i in array){ system("cd "array[i]" && echo $PWD") } }'Une amélioration de la version plutôt sympa de @ ernest-a:
absolute_path() {
    cd "$(dirname "$1")"
    case $(basename $1) in
        ..) echo "$(dirname $(pwd))";;
        .)  echo "$(pwd)";;
        *)  echo "$(pwd)/$(basename $1)";;
    esac
}Cela traite correctement le cas où se trouve le dernier élément du chemin .., auquel cas la "$(pwd)/$(basename "$1")"réponse de in @ ernest-a apparaîtra comme accurate_sub_path/spurious_subdirectory/...
Si vous souhaitez transformer une variable contenant un chemin relatif en un chemin absolu, cela fonctionne:
   dir=`cd "$dir"`"cd" fait écho sans changer le répertoire de travail, car exécuté ici dans un sous-shell.
dir=`cd ".."` && echo $dir
                    Il s'agit d'une solution chaînée de toutes les autres, par exemple, en cas d' realpathéchec, soit parce qu'elle n'est pas installée, soit parce qu'elle se termine avec un code d'erreur, la solution suivante est tentée jusqu'à ce qu'elle obtienne le bon chemin.
#!/bin/bash
function getabsolutepath() {
    local target;
    local changedir;
    local basedir;
    local firstattempt;
    target="${1}";
    if [ "$target" == "." ];
    then
        printf "%s" "$(pwd)";
    elif [ "$target" == ".." ];
    then
        printf "%s" "$(dirname "$(pwd)")";
    else
        changedir="$(dirname "${target}")" && basedir="$(basename "${target}")" && firstattempt="$(cd "${changedir}" && pwd)" && printf "%s/%s" "${firstattempt}" "${basedir}" && return 0;
        firstattempt="$(readlink -f "${target}")" && printf "%s" "${firstattempt}" && return 0;
        firstattempt="$(realpath "${target}")" && printf "%s" "${firstattempt}" && return 0;
        # If everything fails... TRHOW PYTHON ON IT!!!
        local fullpath;
        local pythoninterpreter;
        local pythonexecutables;
        local pythonlocations;
        pythoninterpreter="python";
        declare -a pythonlocations=("/usr/bin" "/bin");
        declare -a pythonexecutables=("python" "python2" "python3");
        for path in "${pythonlocations[@]}";
        do
            for executable in "${pythonexecutables[@]}";
            do
                fullpath="${path}/${executable}";
                if [[ -f "${fullpath}" ]];
                then
                    # printf "Found ${fullpath}\\n";
                    pythoninterpreter="${fullpath}";
                    break;
                fi;
            done;
            if [[ "${pythoninterpreter}" != "python" ]];
            then
                # printf "Breaking... ${pythoninterpreter}\\n"
                break;
            fi;
        done;
        firstattempt="$(${pythoninterpreter} -c "import os, sys; print( os.path.abspath( sys.argv[1] ) );" "${target}")" && printf "%s" "${firstattempt}" && return 0;
        # printf "Error: Could not determine the absolute path!\\n";
        return 1;
    fi
}
printf "\\nResults:\\n%s\\nExit: %s\\n" "$(getabsolutepath "./asdfasdf/ asdfasdf")" "${?}"Vous pouvez utiliser la substitution de chaîne bash pour n'importe quel chemin relatif $ line:
line=$(echo ${line/#..\//`cd ..; pwd`\/})
line=$(echo ${line/#.\//`pwd`\/})
echo $lineLa substitution de base avant de chaîne suit la formule 
$ {string / # substring / replacement}
 
qui est bien discutée ici: https://www.tldp.org/LDP/abs/html/string-manipulation.html
Le \caractère annule le /lorsque nous voulons qu'il fasse partie de la chaîne que nous trouvons / remplaçons.
Je n'ai pas pu trouver une solution parfaitement portable entre Mac OS Catalina, Ubuntu 16 et Centos 7, j'ai donc décidé de le faire avec python inline et cela a bien fonctionné pour mes scripts bash.
to_abs_path() {
  python -c "import os; print os.path.abspath('$1')"
}
to_abs_path "/some_path/../secrets"