comando bash / fish para imprimir la ruta absoluta a un archivo

Pregunta: ¿hay un comando simple sh / bash / zsh / fish / … para imprimir la ruta absoluta de cualquier archivo que alimente?

Caso de uso: estoy en el directorio /a/b y me gustaría imprimir la ruta completa al archivo c en la línea de comandos para poder pegarlo fácilmente en otro progtwig: /a/b/c . Simple, pero un pequeño progtwig para hacer esto probablemente me podría ahorrar 5 o menos segundos cuando se trata de manejar rutas largas, que al final se acumula. Entonces, me sorprende que no pueda encontrar una utilidad estándar para hacer esto, ¿realmente no hay ninguno?

Aquí hay una implementación de muestra, 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) 

Prueba realpath .

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

Pruebe readlink que resolverá los enlaces simbólicos:

 readlink -e /foo/bar/baz 
 #! /bin/sh echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")" 
 $ readlink -m FILE /path/to/FILE 

Esto es mejor que readlink -e FILE o realpath , porque funciona incluso si el archivo no existe.

Olvídese de readlink y realpath que pueden o no estar instalados en su sistema.

Expandir la respuesta de dogbane aquí arriba se expresa como una función:

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

puedes usarlo así:

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

¿Cómo y por qué funciona?

La solución explota el hecho de que el comando pwd incorporado de Bash imprimirá la ruta absoluta del directorio actual cuando se invoca sin argumentos.

¿Por qué me gusta esta solución?

Es portátil y no requiere ni readlink ni realpath que a menudo no existe en una instalación predeterminada de una distribución de Linux / Unix dada.

¿Qué pasa si el directorio no existe?

Como se indicó anteriormente, la función fallará y se imprimirá en stderr si la ruta de directorio dada no existe. Esto puede no ser lo que quieres. Puede expandir la función para manejar esa situación:

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

Ahora devolverá una cadena vacía si uno de los directorios principales no existe.

¿Cómo se maneja el seguimiento de ‘..’ o ‘.’ en la entrada?

Bueno, da un camino absoluto en ese caso, pero no es mínimo. Se verá así:

 /Users/bob/Documents/.. 

Si quieres resolver el ‘…’ necesitarás hacer que el script sea como sigue:

 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 } 

Esta ruta relativa a la función de shell convertidor de ruta absoluta

  • no requiere utilidades (solo cd y pwd )
  • funciona para directorios y archivos
  • maneja .. y .
  • maneja espacios en dir o nombres de archivos
  • requiere que exista un archivo o directorio
  • no devuelve nada si no existe nada en el camino dado
  • maneja rutas absolutas como entrada (las pasa esencialmente)

Código:

 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 } 

Muestra:

 # 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 

Nota: Esto se basa en las respuestas de nolan6000 y bsingh , pero corrige el caso del archivo.

También entiendo que la pregunta original era sobre una utilidad de línea de comando existente. Pero como esta parece ser LA pregunta sobre stackoverflow para eso, incluyendo scripts de shell que quieren tener dependencias mínimas, puse esta solución de script aquí, para que pueda encontrarla más tarde 🙂

El comando find puede ayudar

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

Enumera todos los archivos dentro o debajo del directorio actual con nombres que coinciden con el patrón. Puede simplificarlo si solo obtiene unos pocos resultados (por ejemplo, el directorio cerca de la parte inferior del árbol que contiene pocos archivos), solo

 find $PWD 

Yo uso esto en Solaris 10, que no tiene las otras utilidades mencionadas.

Si no tiene las utilidades readlink o realpath, puede usar la siguiente función que funciona en bash y zsh (no está seguro del rest).

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

Esto también funciona para archivos inexistentes (como lo hace la función python os.path.abspath ).

Lamentablemente, abspath ./../somefile no elimina los puntos.

Aquí hay una función de solo zsh que me gusta por su tamaño compacto. Utiliza el modificador de expansión ‘A’ – ver zshexpn (1).

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

En general, no existe la absolute path a un archivo (esta afirmación significa que puede haber más de uno en general, por lo tanto, el uso del artículo definido no es apropiado). Una absolute path es cualquier ruta que comience desde la raíz “/” y designe un archivo sin ambigüedad independientemente del directorio de trabajo (consulte, por ejemplo, wikipedia ).

Una relative path es una ruta que debe interpretarse a partir de otro directorio. Puede ser el directorio de trabajo si es una relative path que está siendo manipulada por una aplicación (aunque no necesariamente). Cuando está en un enlace simbólico en un directorio, por lo general se pretende que sea relativo a ese directorio (aunque el usuario puede tener otros usos en mente).

Por lo tanto, una ruta absoluta es solo una ruta relativa al directorio raíz.

Una ruta (absoluta o relativa) puede o no contener enlaces simbólicos. Si no lo hace, también es algo impermeable a los cambios en la estructura de enlace, pero esto no es necesariamente necesario o incluso deseable. Algunas personas llaman canonical path (o canonical file name o resolved path ) una absolute path en la que todos los enlaces simbólicos se han resuelto, es decir, han sido reemplazados por una ruta a la que se enlazan. Los comandos realpath y readlink buscan una ruta canónica, pero solo realpath tiene una opción para obtener una ruta absoluta sin molestarse en resolver enlaces simbólicos (junto con varias otras opciones para obtener varios tipos de rutas, absolutas o relativas a algún directorio).

Esto requiere varias observaciones:

  1. los enlaces simbólicos solo se pueden resolver si se crea lo que se supone que deben vincular, lo que obviamente no siempre es el caso. Los comandos realpath y readlink tienen opciones para dar cuenta de eso.
  2. un directorio en una ruta puede convertirse más adelante en un enlace simbólico, lo que significa que la ruta ya no es canonical . Por lo tanto, el concepto depende del tiempo (o del entorno).
  3. incluso en el caso ideal, cuando se pueden resolver todos los enlaces simbólicos, aún puede haber más de una canonical path a un archivo, por dos razones:
    • la partición que contiene el archivo puede haberse montado simultáneamente ( ro ) en varios puntos de assembly.
    • puede haber enlaces duros al archivo, lo que significa esencialmente que el archivo existe en varios directorios diferentes.

Por lo tanto, incluso con la definición mucho más restrictiva de la canonical path , puede haber varias rutas canónicas a un archivo. Esto también significa que el calificador canonical es algo inadecuado ya que generalmente implica una noción de unicidad.

Esto amplía una breve discusión del tema en una respuesta a otra pregunta similar en Bash: recuperar la ruta absoluta dada relativa

Mi conclusión es que realpath está mejor diseñado y es mucho más flexible que readlink . El único uso de readlink que no está cubierto por realpath es la llamada sin opción que devuelve el valor de un enlace simbólico.

Para los directorios dirname se activa para ../ y devuelve ./ .

La función de nolan6000 se puede modificar para corregir eso:

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

He colocado la siguiente secuencia de comandos en mi sistema y la llamo como un alias de bash para cuando quiera obtener rápidamente la ruta completa a un archivo en el directorio actual:

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

No estoy seguro de por qué, pero en OS X, cuando lo llama un script, “$ PWD” se expande a la ruta absoluta. Cuando se llama al comando find en la línea de comando, no lo hace. Pero hace lo que quiero … disfrutar.

La respuesta dogbane con la descripción de lo que está sucediendo:

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

Explicación:

  1. Este script obtiene ruta relativa como argumento "$1"
  2. Luego, obtenemos el nombre del directorio como parte de esa ruta (puede pasar el directorio o el archivo a este script): dirname "$1"
  3. Luego, cd "$(dirname "$1") en este directorio relativo y obtenemos una ruta absoluta ejecutando el comando pwd shell
  4. Después de eso, agregamos basename a la ruta absoluta: $(basename "$1")
  5. Como paso final lo hacemos echo
 #! /bin/bash file="$@" realpath "$file" 2>/dev/null || eval realpath $(echo $file | sed 's/ /\\ /g') 

Esto compensa las deficiencias de realpath , guárdelo en un script de shell fullpath . Ahora puede llamar:

 $ 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. 

Esta no es una respuesta a la pregunta, sino para aquellos que sí lo hacen:

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

maneja / .. ./ etc correctamente. También parece que trabajo en OSX

Una alternativa para obtener el camino absoluto en Ruby :

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

Funciona sin argumentos (carpeta actual) y la ruta de archivo o carpeta relativa y absoluta como elemento de prueba.

Hola chicos, sé que es un tema viejo, pero solo estoy publicando esto como referencia para cualquier otra persona que haya visitado esto como yo. Si entendí la pregunta correctamente, creo que el comando locate $filename . Muestra la ruta absoluta del archivo proporcionado, pero solo si existe.