web-dev-qa-db-fra.com

commande bash / fish pour imprimer le chemin absolu d'un fichier

Question: existe-t-il une simple commande sh/bash/zsh/fish/... permettant d’imprimer le chemin absolu du fichier que je l’alimente?

Cas d'utilisation: je suis dans le répertoire /a/b et j'aimerais imprimer le chemin complet du fichier c sur la ligne de commande afin de pouvoir le coller facilement dans un autre programme: /a/b/c. Simple, mais un petit programme pour faire cela pourrait probablement me faire gagner environ 5 secondes quand il s’agit de gérer de longs chemins, ce qui au final s’additionne. Donc, cela me surprend que je ne trouve pas d’utilitaire standard pour le faire - n’y at-il vraiment aucun?

Voici un exemple d'implémentation, abspath.py:

#!/usr/bin/python
# Author: Diggory Hardy <[email protected]>
# Licence: public domain
# Purpose: print the absolute path of all input paths

import sys
import os.path
if len(sys.argv)>1:
    for i in range(1,len(sys.argv)):
        print os.path.abspath( sys.argv[i] )
    sys.exit(0)
else:
    print >> sys.stderr, "Usage: ",sys.argv[0]," PATH."
    sys.exit(1)
384
dhardy

Essayez realpath.

$ realpath example.txt
/home/username/example.txt
464
Benjamin Bannier

Essayez readlink qui résoudra les liens symboliques:

readlink -e /foo/bar/baz
297
Dennis Williamson
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"
231
dogbane

Oubliez readlink et realpath qui peuvent être installés ou non sur votre système.

Développer sur réponse de dogbane ci-dessus, ici, il est exprimé en fonction:

#!/bin/bash
get_abs_filename() {
  # $1 : relative filename
  echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
}

vous pouvez ensuite l'utiliser comme ceci:

myabsfile=$(get_abs_filename "../../foo/bar/file.txt")

Comment et pourquoi ça marche?

La solution exploite le fait que la commande intégrée Bash pwd imprimera le chemin absolu du répertoire en cours lorsqu'elle est appelée sans arguments.

Pourquoi j'aime cette solution?

Il est portable et ne nécessite ni readlink ni realpath qui n’existent souvent pas lors d’une installation par défaut d’une distribution Linux/Unix donnée.

Et si dir n'existe pas?

Comme indiqué ci-dessus, la fonction échouera et imprimera sur stderr si le chemin du répertoire indiqué n'existe pas. Cela peut ne pas être ce que vous voulez. Vous pouvez développer la fonction pour gérer cette situation:

#!/bin/bash
get_abs_filename() {
  # $1 : relative filename
  if [ -d "$(dirname "$1")" ]; then
    echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
  fi
}

Maintenant, il retournera une chaîne vide si les répertoires parents n'existent pas.

Comment gérez-vous la fuite '..' ou '.' en entrée?

Eh bien, dans ce cas, cela donne un chemin absolu, mais pas minimal. Cela ressemblera à:

/Users/bob/Documents/..

Si vous voulez résoudre le '..' vous devrez faire le script comme suit:

get_abs_filename() {
  # $1 : relative filename
  filename=$1
  parentdir=$(dirname "${filename}")

  if [ -d "${filename}" ]; then
      echo "$(cd "${filename}" && pwd)"
  Elif [ -d "${parentdir}" ]; then
    echo "$(cd "${parentdir}" && pwd)/$(basename "${filename}")"
  fi
}
76
peterh
$ readlink -m FILE
/path/to/FILE

C'est mieux que readlink -e FILE ou realpath, car cela fonctionne même si le fichier n'existe pas.

74
Flimm

Ce chemin relatif au convertisseur de chemin absolu Fonction Shell

  • ne nécessite aucun utilitaire (juste cd et pwd)
  • fonctionne pour les répertoires et les fichiers
  • gère .. et .
  • gère les espaces dans les noms de fichiers ou de répertoires
  • nécessite que le fichier ou le répertoire existe
  • ne retourne rien si rien n'existe sur le chemin donné
  • gère les chemins absolus en entrée (les passe essentiellement)

Code:

function abspath() {
    # generate absolute path from relative path
    # $1     : relative filename
    # return : absolute path
    if [ -d "$1" ]; then
        # dir
        (cd "$1"; pwd)
    Elif [ -f "$1" ]; then
        # file
        if [[ $1 = /* ]]; then
            echo "$1"
        Elif [[ $1 == */* ]]; then
            echo "$(cd "${1%/*}"; pwd)/${1##*/}"
        else
            echo "$(pwd)/$1"
        fi
    fi
}

Échantillon:

# assume inside /parent/cur
abspath file.txt        => /parent/cur/file.txt
abspath .               => /parent/cur
abspath ..              => /parent
abspath ../dir/file.txt => /parent/dir/file.txt
abspath ../dir/../dir   => /parent/dir          # anything cd can handle
abspath doesnotexist    =>                      # empty result if file/dir does not exist
abspath /file.txt       => /file.txt            # handle absolute path input

Remarque: Ceci est basé sur les réponses de nolan60 et bsingh , mais corrige la casse du fichier.

Je comprends aussi que la question initiale concernait un utilitaire de ligne de commande existant. Mais puisque cela semble être LA question sur stackoverflow pour cela, y compris les scripts Shell qui veulent avoir des dépendances minimales, je mets cette solution de script ici, afin que je puisse la trouver plus tard:)

62

La commande find peut aider

find $PWD -name ex*
find $PWD -name example.log

Répertorie tous les fichiers situés dans ou sous le répertoire actuel avec des noms correspondant au modèle. Vous pouvez le simplifier si vous n’obtenez que quelques résultats (par exemple, un répertoire au bas de l’arbre contenant quelques fichiers),

find $PWD

J'utilise ceci sur Solaris 10, qui ne contient pas les autres utilitaires mentionnés.

23
lessthanideal

Si vous n'avez pas d'utilitaires readlink ou realpath, vous pouvez utiliser la fonction suivante qui fonctionne dans bash et zsh (pas sûr du reste).

abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; esac; }

Cela fonctionne également pour les fichiers inexistants (comme la fonction python _ os.path.abspath).

Malheureusement, abspath ./../somefile ne supprime pas les points.

15
hluk

Voici une fonction uniquement zsh que j'aime pour sa compacité. Il utilise le modificateur d’expansion ‘A’ - voir zshexpn (1).

realpath() { for f in "$@"; do echo ${f}(:A); done }
9
wjv

Il n’existe généralement pas de le absolute path dans un fichier (cette déclaration signifie qu’il peut y en avoir plus d’un en général, d’où le l'utilisation de l'article défini le n'est pas appropriée). Un absolute path est un chemin commençant par la racine "/" et désignant un fichier sans ambiguïté indépendamment du répertoire de travail (voir par exemple wikipedia ).

Un relative path est un chemin à interpréter à partir d'un autre répertoire. Il peut s'agir du répertoire de travail s'il s'agit d'un relative path manipulé par une application (mais pas nécessairement). Lorsqu'il se trouve dans un lien symbolique dans un répertoire, il est généralement destiné à être relatif à ce répertoire (bien que l'utilisateur puisse avoir d'autres utilisations à l'esprit).

Par conséquent, un chemin absolu est simplement un chemin relatif au répertoire racine.

Un chemin (absolu ou relatif) peut contenir ou non des liens symboliques. Si ce n'est pas le cas, il est également quelque peu imperméable aux modifications de la structure de liaison, mais cela n'est pas nécessairement requis ni même souhaitable. Certaines personnes appellent canonical path (ou canonical file name ou resolved path) un absolute path dans lequel tous les liens symboliques ont été résolus, c'est-à-dire qu'ils ont été remplacés par un chemin d'accès, quel que soit leur lien. Les commandes realpath et readlink recherchent toutes les deux un chemin canonique, mais seul realpath a une option permettant d’obtenir un chemin absolu sans se soucier de résoudre les liens symboliques (ainsi que plusieurs autres options permettant d'obtenir divers type de chemin, absolu ou relatif à un répertoire).

Cela appelle plusieurs remarques:

  1. les liens symboliques ne peuvent être résolus que s'ils ont déjà été créés, ce qui n'est évidemment pas toujours le cas. Les commandes realpath et readlink ont des options pour rendre compte de cela.
  2. un répertoire sur un chemin peut ensuite devenir un lien symbolique, ce qui signifie que le chemin n'est plus canonical. Par conséquent, le concept dépend du temps (ou de l'environnement).
  3. même dans le cas idéal, lorsque tous les liens symboliques peuvent être résolus, il peut toujours y avoir plus d'un canonical path dans un fichier, pour deux raisons:
    • la partition contenant le fichier peut avoir été montée simultanément (ro) sur plusieurs points de montage.
    • il peut y avoir des liens durs vers le fichier, ce qui signifie essentiellement que le fichier existe dans plusieurs répertoires différents.

Par conséquent, même avec la définition beaucoup plus restrictive de canonical path, il peut y avoir plusieurs chemins canoniques vers un fichier. Cela signifie également que le qualificatif canonical est quelque peu insuffisant puisqu'il implique généralement une notion d'unicité.

Cela développe une brève discussion du sujet dans une réponse à une autre question similaire à Bash: récupérer le chemin absolu donné relatif

Ma conclusion est que realpath est mieux conçu et beaucoup plus souple que readlink. La seule utilisation de readlink qui n'est pas couverte par realpath est l'appel sans option qui renvoie la valeur d'un lien symbolique.

7
babou

La dogbaneréponse avec la description de ce qui va arriver:

#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"

Explication:

  1. Ce script obtient un chemin relatif en tant qu'argument "$1"
  2. Ensuite nous obtenons dirname une partie de ce chemin (vous pouvez passer soit dir ou fichier à ce script): dirname "$1"
  3. Puis nous cd "$(dirname "$1") dans ce répertoire relatif et obtenons son chemin absolu en exécutant la commande pwd Shell
  4. Après cela, nous ajoutons le nom de base au chemin absolu: $(basename "$1")
  5. En dernière étape, nous echo il
3
Eugen Konkov

Ce n'est pas une réponse à la question, mais pour ceux qui font du script:

echo `cd "$1" 2>/dev/null&&pwd||(cd "$(dirname "$1")";pwd|sed "s|/*\$|/${1##*/}|")`

il gère/.. ./ etc correctement. Je semble aussi travailler sur OSX

2
Alek

Pour les répertoires dirname est déclenché pour ../ et renvoie ./.

fonction de nolan60 peut être modifié pour résoudre ce problème:

get_abs_filename() {
  # $1 : relative filename
  if [ -d "${1%/*}" ]; then
    echo "$(cd ${1%/*}; pwd)/${1##*/}"
  fi
}
2
bsingh

J'ai placé le script suivant sur mon système et je l'appelle comme un alias bash lorsque je veux saisir rapidement le chemin complet d'un fichier dans le répertoire en cours:

#!/bin/bash
/usr/bin/find "$PWD" -maxdepth 1 -mindepth 1 -name "$1"

Je ne sais pas pourquoi, mais sous OS X, lorsqu'il est appelé par un script, "$ PWD" se développe sur le chemin absolu. Lorsque la commande find est appelée sur la ligne de commande, ce n'est pas le cas. Mais ça fait ce que je veux ... profiter.

2
fred.johnsen
#! /bin/bash

file="$@"
realpath "$file" 2>/dev/null || eval realpath $(echo $file | sed 's/ /\\ /g')

Ceci compense les inconvénients de realpath, enregistrez-le dans un script shell fullpath. Vous pouvez maintenant appeler:

$ cd && touch a\ a && rm A 2>/dev/null 
$ fullpath "a a"
/home/user/a a
$ fullpath ~/a\ a
/home/user/a a
$ fullpath A
A: No such file or directory.
1
ShellFish

Une alternative pour obtenir le chemin absolu dans Ruby:

realpath() {Ruby -e "require 'Pathname'; puts Pathname.new('$1').realpath.to_s";}

Fonctionne sans argument (dossier actuel) et les chemins de fichiers ou de dossiers relatifs et absolus en tant qu'agument.

1
Atika