commande bash / fish pour imprimer le chemin absolu vers un fichier

Question: existe-t-il une simple commande sh / bash / zsh / fish / … pour imprimer le chemin absolu du fichier que je lui donne?

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 pour pouvoir le coller facilement dans un autre programme: /a/b/c . Simple, mais un petit programme pour le faire pourrait probablement me faire économiser environ 5 secondes quand il s’agit de gérer de longs chemins, ce qui s’ajoute à la fin. Donc, cela me surprend que je ne trouve pas un utilitaire standard pour faire cela – est-ce qu’il n’y en a vraiment pas?

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

 #!/usr/bin/python # Author: Diggory Hardy  # 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) 

Essayez realpath .

 ~ $ realpath example.txt /home/username/example.txt 

Essayez readlink qui résoudra les liens symboliques:

 readlink -e /foo/bar/baz 
 #! /bin/sh echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")" 
 $ 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.

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

En développant la réponse de Dogbane ci-dessus, elle s’exprime comme une fonction:

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

vous pouvez alors 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 pwd intégrée à Bash pwd le chemin absolu du répertoire en cours lorsqu’il est appelé sans arguments.

Pourquoi j’aime cette solution?

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

Et si dir n’existe pas?

Comme indiqué ci-dessus, la fonction échouera et imprimera sur stderr si le chemin de répertoire indiqué n’existe pas. Ce n’est peut-être pas 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 l’une des répertoires parent n’existe pas.

Comment gérez-vous le “..” ou “.” en entrée?

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

 /Users/bob/Documents/.. 

Si vous voulez résoudre le “..”, vous devrez créer 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 } 

Ce chemin relatif à la fonction de shell du convertisseur de chemin absolu

  • ne nécessite aucun utilitaire (juste cd et pwd )
  • fonctionne pour les répertoires et les fichiers
  • poignées .. et .
  • gère les espaces dans dir ou noms de fichiers
  • exige 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 transmet 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 nolan6000 et bsingh , mais corrige la casse du fichier.

Je comprends également que la question initiale concernait un utilitaire de ligne de commande existant. Mais comme 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, donc je peux la retrouver plus tard 🙂

La commande find peut aider

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

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

 find $PWD 

Je l’utilise sur Solaris 10, dont les autres utilitaires ne sont pas mentionnés.

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 rest).

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

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

Malheureusement, abspath ./../somefile ne se débarrasse pas des points.

Voici une fonction zsh-only 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 } 

Il n’existe généralement pas de absolute path vers un fichier (cette instruction signifie qu’il peut y en avoir plusieurs en général, d’où l’utilisation de l’article défini, ce qui n’est pas approprié). Un absolute path est un chemin qui part de la racine “/” et désigne 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. Ce peut être le 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).

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

Un chemin (absolu ou relatif) peut ou non contenir des liens symboliques. Si ce n’est pas le cas, il est également quelque peu insensible aux modifications de la structure de liaison, mais cela n’est pas nécessairement requirejs ni même souhaitable. Certaines personnes appellent le canonical path (ou canonical file name ou le 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 vers lequel ils sont liés. Les commandes realpath et readlink recherchent toutes les deux un chemin canonique, mais seul realpath a la possibilité d’obtenir un chemin absolu sans se soucier de résoudre les liens symboliques (avec plusieurs autres options pour obtenir différents types de chemins, absolus ou relatifs).

Cela appelle plusieurs remarques:

  1. les liens symboliques ne peuvent être résolus que si ce à quoi ils sont censés être liés est déjà créé, ce qui n’est évidemment pas toujours le cas. Les commandes realpath et readlink ont des options pour en tenir compte.
  2. un répertoire sur un chemin peut ensuite devenir un lien symbolique, ce qui signifie que le chemin n’est plus canonical . Le concept est donc dépendant 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 vers un fichier, pour deux raisons:
    • la partition contenant le fichier peut avoir été montée simultanément ( ro ) sur plusieurs points de assembly.
    • 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 ressortingctive du canonical path , il peut y avoir plusieurs chemins canoniques vers un fichier. Cela signifie également que le qualificatif canonical est quelque peu inadéquat car il implique généralement une notion d’unicité.

Cela élargit 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 flexible que readlink . La seule utilisation de readlink qui n’est pas couverte par realpath est l’appel sans option renvoyant la valeur d’un lien symbolique.

Pour les répertoires, dirname se déclenche pour ../ et retourne ./ .

La fonction nolan6000 peut être modifiée pour corriger cela:

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

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, quand 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.

Le dogbane répond avec la description de ce qui se passe:

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

Explication:

  1. Ce script obtient le chemin relatif comme argument "$1"
  2. Ensuite, nous obtenons la partie dirname de ce chemin (vous pouvez transmettre soit dir soit file à ce script): dirname "$1"
  3. Ensuite, nous cd "$(dirname "$1") dans ce cd "$(dirname "$1") relatif et obtenons un chemin absolu en exécutant la commande shell pwd
  4. Après cela, nous ajoutons basename au chemin absolu: $(basename "$1")
  5. Comme dernière étape, nous y faisons echo
 #! /bin/bash file="$@" realpath "$file" 2>/dev/null || eval realpath $(echo $file | sed 's/ /\\ /g') 

Cela compense les lacunes de realpath , stockez-le dans un script shell fullpath . Vous pouvez maintenant appeler:

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

Ce n’est pas une réponse à la question, mais pour ceux qui font des scripts:

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

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

Une alternative pour obtenir le chemin absolu dans Ruby :

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

Fonctionne sans arguments (dossier actuel) et chemin relatif ou absolu du fichier ou du dossier en tant qu’agument.

Hé les gars, je sais que c’est un vieux sujet mais je ne fais que poster ceci pour référence à quelqu’un d’autre qui a visité ce site comme moi. Si j’ai bien compris la question, je pense que la commande locate $filename . Il affiche le chemin absolu du fichier fourni, mais seulement s’il existe.