Obtener la ruta del directorio de archivos de la ruta del archivo

400

En Bash, si VAR="/home/me/mydir/file.c", ¿cómo consigo "/home/me/mydir"?

Talespin_Kit
fuente

Respuestas:

649

dirnamey basenameson las herramientas que está buscando para extraer componentes de ruta:

$ VAR=/home/me/mydir/file.c

$ DIR=$(dirname "${VAR}")

$ echo "${DIR}"
/home/me/mydir

$ basename "${VAR}"
file.c

No son comandos internos de Bash, pero son parte del estándar POSIX (ver dirname, basename) y, por lo tanto, deberían estar disponibles en la gran mayoría de los sistemas que ejecutarán Bash.

paxdiablo
fuente
44
¿Por qué el uso de corchetes alrededor de los nombres de las variables, y no "$ VAR" por ejemplo?
user658182
1
stackoverflow.com/questions/8748831/… responde la pregunta anterior.
user658182
1
@ user658182 En este ejemplo en particular, se hace por costumbre, no por necesidad.
Carrito abandonado el
95
$ export VAR=/home/me/mydir/file.c
$ export DIR=${VAR%/*}
$ echo "${DIR}"
/home/me/mydir

$ echo "${VAR##*/}"
file.c

Para evitar la dependencia con basenameydirname

Emmanuel Devaux
fuente
3
Como ambos son parte de POSIX, una dependencia no debería ser un problema.
Orkoden
1
Orkoden, tienes razón. El objetivo de mi respuesta es mostrar que no hay obligación de ejecutar dos procesos adicionales. bash es autosuficiente para el caso de uso.
Emmanuel Devaux
2
Estoy usando el método de Emmanuel porque deseo pasar un archivo o un nombre de carpeta, y luego calcular la ruta de la carpeta. El uso de esta expresión regular hace lo correcto, mientras que la función dirname devolvió la carpeta principal cuando ingresé una carpeta.
AnneTheAgile
8
Sin embargo, si no hay información de ruta en $ VAR, $ {VAR% / *} / test produce un valor inesperado igual a $ VAR / test mientras que $ (dirname $ VAR) producirá el valor más predecible y apropiado de ./test. Esto es un gran problema porque el primero intentará tratar el nombre de archivo como un directorio, mientras que el segundo estará bien.
davemyron
19

En una nota relacionada, si solo tiene el nombre de archivo o la ruta relativa, dirnamepor sí solo no ayudará. Para mí, la respuesta terminó siendo readlink.

fname='txtfile'    
echo $(dirname "$fname")                # output: .
echo $(readlink -f "$fname")            # output: /home/me/work/txtfile

Luego puede combinar los dos para obtener solo el directorio.

echo $(dirname $(readlink -f "$fname")) # output: /home/me/work
jerblack
fuente
1
Si no existía más de un componente de ruta, debe utilizar readlink -m "$fname"para
canonizar el
7

Si le importa que los archivos de destino sean un enlace simbólico, primero puede verificarlo y obtener el archivo original. La siguiente cláusula if puede ayudarlo.

if [ -h $file ]
then
 base=$(dirname $(readlink $file))
else
 base=$(dirname $file)
fi
Tahsin Turkoz
fuente
5

Estaba jugando con esto y se me ocurrió una alternativa.

$ VAR=/home/me/mydir/file.c

$ DIR=`echo $VAR |xargs dirname`

$ echo $DIR
/home/me/mydir

La parte que me gustó es que fue fácil extender la copia de seguridad del árbol:

$ DIR=`echo $VAR |xargs dirname |xargs dirname |xargs dirname`

$ echo $DIR
/home
Eurospoofer
fuente
1

Aquí hay un script que utilicé para el recorte recursivo. Reemplace $ 1 con el directorio que desee, por supuesto.

BASEDIR="$1"
IFS=$'\n'
cd $BASEDIR
 for f in $(find . -type f -name ' *')
 do 
    DIR=$(dirname "$f")
    DIR=${DIR:1}
    cd $BASEDIR$DIR
    rename 's/^ *//' *
 done
kmchen
fuente
0

Primero, lo he reemplazado /con un espacio vacío ( ). Luego, eliminé todos los caracteres antes de cualquier espacio vacío ( ). Al final, eliminé el primer carácter que es el espacio vacío ( ).

$ VAR="/home/me/mydir/file.c"

$ echo $VAR | tr '/' ' ' | sed 's/^.* / /' | cut -c2-
file.c
alper
fuente
0
HERE=$(cd $(dirname $BASH_SOURCE) && pwd)

donde obtienes la ruta completa con new_path = $(dirname ${BASH_SOURCE[0]}). Cambia el directorio actual con cd new_path y luego ejecuta pwdpara obtener la ruta completa al directorio actual.

aerijman
fuente