script - variables en bash
Comando bash/fish para imprimir la ruta absoluta a un archivo (17)
Pregunta: ¿hay un simple comando sh / bash / zsh / fish / ... para imprimir la ruta absoluta de cualquier archivo que lo 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 programa: /a/b/c
. Simple, pero un pequeño programa para hacer esto probablemente me ahorrará unos 5 segundos cuando se trata de manejar caminos largos, lo que al final se suma. Entonces, me sorprende que no pueda encontrar una utilidad estándar para hacer esto. ¿Realmente no hay ninguna?
Aquí hay una implementación de ejemplo, 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)
Aquí hay una función solo zsh que me gusta por su compacidad. Utiliza el modificador de expansión ''A'' - vea zshexpn (1).
realpath() { for f in "$@"; do echo ${f}(:A); done }
El comando find
puede ayudar
find $PWD -name ex*
find $PWD -name example.log
Enumera todos los archivos en 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
Lo uso en Solaris 10, que no tiene las otras utilidades mencionadas.
Esta no es una respuesta a la pregunta, pero para aquellos que hacen scripts:
echo `cd "$1" 2>/dev/null&&pwd||(cd "$(dirname "$1")";pwd|sed "s|/*/$|/${1##*/}|")`
maneja / ... ./ etc correctamente. También parece que funciona en OSX.
Esta ruta relativa a la función de shell convertidor de ruta absoluta
- no requiere utilidades (solo
cd
ypwd
) - Trabajos para directorios y archivos.
- manijas
..
y.
- Maneja espacios en dir o nombres de archivos
- requiere que el archivo o directorio exista
- 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 comandos existente. Pero ya que esta parece ser LA pregunta en para eso, incluidos los scripts de shell que desean tener dependencias mínimas, pongo esta solución de script aquí, para poder encontrarla más adelante :)
Generalmente no existe tal cosa como la absolute path
de absolute path
a un archivo (esta declaració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 se inicie desde la raíz "/" y designe un archivo sin ambigüedad independientemente del directorio de trabajo (vea por ejemplo wikipedia ).
Una relative path
es una ruta que debe interpretarse comenzando desde 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, generalmente está destinado a ser 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 a la canonical path
(o al canonical file name
o la resolved path
) una absolute path
en la que se han resuelto todos los enlaces simbólicos, es decir, han sido reemplazados por una ruta a la que están vinculados. 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 varios comentarios:
- los enlaces simbólicos solo se pueden resolver si lo que se supone que están vinculados ya está creado, lo que obviamente no siempre es así. Los comandos
realpath
yreadlink
tienen opciones para dar cuenta de eso. - un directorio en una ruta puede convertirse más tarde 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). - incluso en el caso ideal, cuando todos los enlaces simbólicos pueden resolverse, todavía 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 montaje. - puede haber enlaces duros al archivo, lo que significa que esencialmente el archivo existe en varios directorios diferentes.
- la partición que contiene el archivo puede haberse montado simultáneamente (
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 singularidad.
Esto expande 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.
He colocado la siguiente secuencia de comandos en mi sistema y la llamo como un alias de bash para cuando quiera capturar 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 se llama mediante una secuencia de comandos "$ PWD" se expande a la ruta absoluta. Cuando el comando de búsqueda se llama en la línea de comandos, no lo hace. Pero hace lo que quiero ... disfrutar.
Hola chicos, se que es un tema antiguo, pero estoy publicando esto como referencia a 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 suministrado, pero solo si existe.
Intente readlink
el enlace que resolverá los enlaces simbólicos:
readlink -e /foo/bar/baz
Olvídese de readlink
y realpath
que pueden o no estar instalados en su sistema.
Ampliando 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")"
}
entonces 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 invoque 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 distro Linux / Unix determinada.
¿Qué pasa si dir no existe?
Como se indicó anteriormente, la función fallará e imprimirá en stderr si la ruta del directorio dada no existe. Esto puede no ser lo que quieres. Puedes 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 no existe uno de los directorios principales.
¿Cómo manejas el ''...'' o ''.'' en la entrada?
Bueno, da un camino absoluto en ese caso, pero no mínimo. Se verá como
/Users/bob/Documents/..
Si desea resolver el ''...'' necesitará hacer el script como:
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
}
Para directorios dirname
se dispara 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
}
Prueba realpath
.
$ realpath example.txt
/home/username/example.txt
Si no tiene las utilidades readlink o realpath, puede usar la siguiente función que funciona en bash y zsh (no estoy seguro del resto).
abspath () { case "$1" in /*)printf "%s/n" "$1";; *)printf "%s/n" "$PWD/$1";; esac; }
Esto también funciona para archivos inexistentes (al igual que la función python os.path.abspath
).
Desafortunadamente, abspath ./../somefile
no elimina los puntos.
The dogbane
answer con la descripción de lo que viene:
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
Explicación:
- Este script obtiene la ruta relativa como argumento
"$1"
- Luego obtenemos la parte dirname de esa ruta (puede pasar dir o file a este script):
dirname "$1"
- Luego,
cd "$(dirname "$1")
en este directorio relativo y obtenemos una ruta de acceso absoluta ejecutando el comandopwd
shell - Después de eso, agregamos el nombre base a la ruta absoluta:
$(basename "$1")
- Como paso final lo hacemos
echo
.
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 una ruta de archivo o carpeta relativa y absoluta como un documento.
#! /bin/bash
file="$@"
realpath "$file" 2>/dev/null || eval realpath $(echo $file | sed ''s/ /// /g'')
Esto compensa las deficiencias de realpath
, guárdelo en una fullpath
shell fullpath
. Ahora puedes llamar:
$ 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.
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd -P)/$(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.