Bash: récupérer le chemin absolu donné relatif

y a-t-il une commande pour récupérer le chemin absolu donné au 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
done
86
demandé sur xuhdev 2010-11-14 02:24:41

16 réponses

utiliser:

find $(pwd)/ -type f

pour obtenir tous les fichiers ou

echo $(pwd)/$line

pour afficher le chemin complet (si le chemin relatif est important)

42
répondu mpapis 2010-11-13 23:34:39

Essayer realpath .

~ $ sudo apt-get install realpath
~ $ realpath .bashrc
/home/username/.bashrc

La réponse vient de " bash/poissons de commande à imprimer chemin absolu vers un fichier ".

92
répondu epere4 2017-05-23 11:47:25

si vous avez le paquet coreutils installé, vous pouvez généralement utiliser readlink -f relative_file_name pour récupérer le paquet absolu (avec tous les liens symboliques résolus)

85
répondu Moritz Bunkus 2014-01-13 13:13:50
#! /bin/sh
echo "$(cd "$(dirname "")"; pwd)/$(basename "")"

UPD des explications

  1. ce script obtient le chemin relatif comme argument ""
  2. puis nous obtenons dirname partie de ce chemin (vous pouvez passer soit dir ou fichier à ce script): dirname ""
  3. puis nous cd "$(dirname "") dans cette dir relative et obtenir le chemin absolu pour elle en exécutant pwd commande shell
  4. après cela nous ajoutons basename à chemin absolu: $(basename "")
  5. comme étape finale nous echo it
35
répondu Eugen Konkov 2016-09-05 10:00:58

pour ce que ça vaut, j'ai voté pour la réponse qui a été choisie, mais je voulais partager une solution. L'inconvénient est que C'est Linux seulement - j'ai passé environ 5 minutes à essayer de trouver L'équivalent OSX avant de venir à Stack overflow. Je suis sûr qu'elle est là, cependant.

sous Linux, vous pouvez utiliser readlink -e en tandem avec dirname .

$(dirname $(readlink -e ../../../../etc/passwd))

rendements

/etc/

Et puis vous utilisez dirname sœur, basename pour obtenir juste le nom du fichier

$(basename ../../../../../passwd)

rendements

passwd

rassemblez tout..

F=../../../../../etc/passwd
echo "$(dirname $(readlink -e $F))/$(basename $F)"

rendements

/etc/passwd

vous êtes en sécurité si vous ciblez un répertoire, basename ne vous retournera rien et vous finirez avec des doubles slashes dans la sortie finale.

26
répondu synthesizerpatel 2014-06-12 17:32:46

je pense que c'est le plus portable:

abspath() {                                               
    cd "$(dirname "")"
    printf "%s/%s\n" "$(pwd)" "$(basename "")"
    cd "$OLDPWD"
}

il échouera si le chemin n'existe pas.

18
répondu Ernest A 2014-01-28 22:43:44

realpath est probablement le meilleur

mais ...

la question initiale était très confuse pour commencer, 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 est dans le titre. La première commande est cette réponse (est-elle vraiment ? Je doute), et pourrait faire aussi bien sans le '/'. Et je ne vois pas ce que la deuxième commande est faire.

plusieurs questions sont mélangées :

  • changer un chemin relatif en un chemin absolu, quel qu'il soit désigne, probablement rien. ( typiquement, si vous émettez une commande telle que touch foo/bar , le le nom de chemin foo/bar doit exister pour vous, et peut-être être utilisé dans calcul, avant que le fichier est créé. )

  • il peut y avoir plusieurs chemin absolu qui dénotent le même fichier (ou fichier potentiel), notamment en raison de liens symboliques (liens symboliques) sur le chemin, mais peut-être pour d'autres raisons (d'un appareil peut être monté deux fois en lecture seule). Un peut ou peut ne pas vouloir résoudre explicitement de tels liens symboliques.

  • arriver au bout d'une chaîne de liens symboliques vers un lien non-symétrique nom de fichier ou de. Ceci peut ou ne peut pas donner un nom de chemin absolu, en fonction de comment il est fait. Et l'on peut, ou ne peut pas voulez résoudre dans un chemin absolu.

La commande readlink foo sans option donne une réponse seulement si son l'argument foo est un lien symbolique, et cette réponse est la valeur de la symbolique. Aucun autre lien est suivi. La réponse peut être un chemin relatif: quelle que soit la valeur de l'argument du lien symbolique.

cependant, readlink a des options (- f-e ou-m) qui fonctionneront pour tous fichiers, et en donner un chemin absolu (l'un avec aucun des liens symboliques) à le fichier indiqué par l'argument.

cela fonctionne très bien pour tout ce qui n'est pas un lien symbolique, bien que l'on pourrait le désir d'utiliser un chemin absolu sans résoudre l'intermédiaire liens symboliques sur le chemin. Ceci est fait par la commande realpath -s foo

dans le cas d'un argument de lien symbolique, readlink avec ses options sera encore résoudre tous les liens symboliques sur le chemin absolu de l'argument, mais que inclura également tous les liens symboliques qui peuvent être rencontrés par suivant la valeur de l'argument. Vous pourriez ne pas vouloir que si vous avez désiré un chemin absolu vers l'argument symlink lui-même, plutôt que vers quoi que ce soit il peut se lier à. Encore une fois, si foo est un lien symbolique, realpath -s foo sera obtenir un chemin absolu sans résoudre les liens symboliques, y compris celui donné en argument.

sans l'option -s , realpath fait à peu près la même chose que readlink , sauf pour simple la lecture de la valeur d'un lien, ainsi que plusieurs d'autres choses. Il n'est tout simplement pas clair pour moi pourquoi readlink a ses options, créant apparemment une redondance indésirable avec realpath .

explorer le web ne dit pas beaucoup plus, sauf qu'il peut y avoir certaines variations entre les systèmes.

Conclusion: realpath est la meilleure commande à utiliser, avec le plus flexibilité, au moins pour l'usage demandé ici.

9
répondu babou 2018-02-21 06:44:20

la réponse D'Eugen n'a pas tout à fait fonctionné pour moi mais cela a fait:

    absolute="$(cd $(dirname $file); pwd)/$(basename $file)"

note latérale, votre répertoire de travail actuel n'est pas affecté.

4
répondu biomiker 2017-02-13 20:45:43

dans le cas de find , il est probablement plus facile de simplement donner le chemin absolu pour qu'il cherche, par exemple:

find /etc
find `pwd`/subdir_of_current_dir/ -type f
2
répondu Arkku 2010-11-13 23:33:04

si vous utilisez bash sur Mac OS X qui n'a pas realpath existant ni son readlink peut imprimer le chemin absolu, vous pouvez avoir le choix mais de coder votre propre version pour l'imprimer. Voici mon implémentation:

(pur bash)

abspath(){
  local thePath
  if [[ ! "" =~ ^/ ]];then
    thePath="$PWD/"
  else
    thePath=""
  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[*]}"
)
}

(utiliser gawk)

abspath_gawk() {
    if [[ -n "" ]];then
        echo |gawk '{
            if(substr("151910920",1,1) != "/"){
                path = ENVIRON["PWD"]"/""151910920"
            } else path = "151910920"
            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
}

(pur 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("151920920")
}

exemple:

$ abspath I/am/.//..//the/./god/../of///.././war
/Users/leon/I/the/war
2
répondu Meow 2014-02-22 07:39:44

ma solution préférée était celle de @EugenKonkov car elle n'impliquait pas la présence d'autres utilitaires (le paquet coreutils).

, Mais il a échoué pour les chemins d'accès relatifs "." et." .", voici donc une version légèrement améliorée traitant ces cas spéciaux.

il échoue toujours si l'utilisateur n'a pas la permission de cd dans le répertoire parent du chemin relatif, cependant.

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

    if [ "$target" == "." ]; then
        echo "$(pwd)"
    elif [ "$target" == ".." ]; then
        echo "$(dirname "$(pwd)")"
    else
        echo "$(cd "$(dirname "")"; pwd)/$(basename "")"
    fi
}
2
répondu hashchange 2018-07-10 11:38:10

ce qu'ils ont dit, sauf find $PWD ou (en bash) find ~+ est un peu plus commode.

0
répondu Tobu 2010-11-13 23:44:12

similaire à la réponse de @ernest-a, mais sans affecter $OLDPWD ou définir une nouvelle fonction, vous pourriez tirer un subshell (cd <path>; pwd)

$ pwd
/etc/apache2
$ cd ../cups 
$ cd -
/etc/apache2
$ (cd ~/..; pwd)
/Users
$ cd -
/etc/cups
0
répondu fakedrake 2015-05-13 09:26:41

si le chemin relatif est un chemin de répertoire, alors essayez mine, devrait être le meilleur:

absPath=$(pushd ../SOME_RELATIVE_PATH_TO_Directory > /dev/null && pwd && popd > /dev/null)

echo $absPath
0
répondu Shunfang Lan 2015-10-13 09:37:55

Si vous voulez transformer une variable contenant un chemin relatif dans l'absolu, cela fonctionne :

   dir=`cd "$dir"`

" cd " fait écho sans changer le répertoire de travail, car exécuté ici dans un sous-shell.

0
répondu Eric H. 2016-08-25 05:21:42
echo "mydir/doc/ mydir/usoe ./mydir/usm" |  awk '{ split("151900920",array," "); for(i in array){ system("cd "array[i]" && echo $PWD") } }'
0
répondu Josh Barton 2018-02-21 10:50:12