Descomponer una ruta en directorios, nombre de archivo y extensión en Bash

Una tarea que puede ser bastante común a la hora de escribir scripts o aplicaciones que trabajen con el sistema de archivos es la necesidad de descomponer una ruta completa del tipo «/directorio/subdirectorio/…/…/archivo.extension» para obtener por separado el nombre de archivo, la extensión y la ruta de directorios. De hecho, fue una de las necesidades que me ha surgido estos días, escribiendo un Shell Script un tanto grande en el que necesitaba obtener el nombre de un archivo de una ruta completa así como la estructura de directorios hasta el mismo.

Dado que me suele gustar, al escribir scripts de cierto tamaño, dividirlos por bloques de código independientes, voy a publicar este como una solución aislada para solventar el problema de descomponer rutas aunque cuando lo volváis a ver en el script que aún no he terminado aparecerá como una función por la comodidad que representan y porque facilitan mucho la lectura del código en scripts de muchas lineas. Sin más preámbulos, vamos manos a la obra:

Dado que este código ahora es independiente, he realizado algunos cambios como que tome la entrada de datos a modo de parametros tras el nombre del script por lo que la ruta a descomponer, deberá ir tras el nombre del script en lo que seria el parámetro $1, es decir, tendriamos que pasárselo de la siguiente manera:

./script.sh /ruta/que/queramos/descomponer/archivo.extension
Por el mismo motivo, lo he dispuesto de forma que la salida del mismo sea la salida estándar mostrando el valor de cada una de las variables que intervienen en el proceso.

También he comentado las lineas relevantes ya que creo que será mejor explicar cada una de las lineas en el mismo punto donde aparece. Así pues, este es el script:

 



#!/bin/bash
# Script para descomponer una ruta completa a un archivo o directorio, obteniendo
# el nombre de archivo y extensión (si existen) y ruta hasta los mismos
for RutaCompleta in $1
do
# Comenzamos extrayendo la parte derecha desde el ultimo caracter "/", es decir, el archivo
NombreArchivo="${RutaCompleta##*/}"
# Longitud de la ruta es el total de caracteres menos el largo del nombre de archivo
LargoRuta="${#RutaCompleta} - ${#NombreArchivo}"
# Extraermos la ruta desde el caracter 0 hasta el caracter final de largo de ruta
RutaSola="${RutaCompleta:0:$LargoRuta}"
# Lo siguiente es extraer nombre de archivo
NombreSolo="${NombreArchivo%.[^.]*}"
# Extension se obtiene eliminando del nombre completo el nombre mas el punto
Extension="${NombreArchivo:${#NombreSolo} + 1}"
# Las 2 lineas anteriores fallan si no hay extension por lo que es necesario comprobar que no
# se de el caso de que haya extension pero no nombre ya que en ese caso la ext seria el nombre
if [[ -z "$NombreSolo" && -n "$Extension" ]]; then
NombreSolo=".$Extension"
Extension=""
fi
done
# Este es el resultado del script
echo
echo "Este es el resultado del script:"
echo
echo La ruta completa es:
echo $RutaCompleta
echo
echo "Ruta.........: \"$RutaSola\""
echo "Nombre.......: \"$NombreSolo\""
echo "Extension....: \"$Extension\""
echo


Si lo ejecutamos, la salida del mismo, según está, sería similar a esto
:

 


$ ./descomp.sh /dir1/subdir1/subdir2/archivo.txt

Este es el resultado del script:

La ruta completa es:
/dir1/subdir1/subdir2/archivo.txt

Ruta………: «/dir1/subdir1/subdir2/»
Nombre…….: «archivo»
Extension….: «txt»


Ahora bien, hay que tener en cuenta que si lo vamos a utilizar como una función llamada desde otro script o simplemente como un bloque de código incrustado entre las lineas, habría que hacerle algunos cambios, pero dado que lo estoy utilizando en otro script que voy a publicar aquí también, no lo explicaré aún ya que es cuestión de tiempo que me toque hacerlo.


 

 

27 Comentarios

  1. Comandos «dirname» y «basename».

  2. A mi me parece más sencillo y claro usar basename y dirname.

  3. Hola iCesofT,
    Lo cierto es que había descartado esos mismos comandos por el mismo motivo que había descartado awk, perl o incluso python, para usarlos en el script, y ciertamente me equivoqué.
    El tema de descartar estos otros métodos de hacerlo era la posibilidad de no estuviesen instalados en algún sistema pero ahí reside mi error ya que no me dio por comprobar a que paquete pertenecían ambos comandos.
    El paquete al que pertenecen es «coreutils», motivo por el cual los podría haber usado perfectamente e incluso habria ahorrado unas lineas de código en el próximo script (Bueno, podría haber ahorrado, no, ahorraré 😉 )

    Todos nos equivocamos y obviamente esta vez me ha tocado 🙂

    No obstante, dependiendo del caso, podría darse la posibilidad de que no se ahorrasen tantas lineas con ellos, me explico:

    Si el fin de las rutas a procesar puede ser tanto un directorio como un archivo y cabe la posibilidad de que no se incluya el carácter «/» al final del último directorio, habria que tratarlo para distinguir si se trata de un directorio o un fichero sin extensión:

    dirname /directorio1/subdirectorio1 –> Devuelve /directorio1
    dirname /directorio1/comando –> Devuelve /directorio1

    basename /directorio1/subdirectorio1 –> Devuelve subdirectorio1 como nombre de archivo

    Ciertamente es un caso bastante concreto que pongo solamente como pequeño apunte (Es el consuelo que me queda, saber que en algún caso sigue siendo útil, después de haber hecho el script :S)

    Sea como sea, gracias por el apunte!

  4. Como ejemplo es muy didáctico, gracias.

  5. wow! Muy interesante todo, la verdad.

  6. Can you e mail me personally with a few ideas about how you have made this web site site seem like this kind of , I’d become appreciative!

  7. estais todos gilipollas o que pasa? el ejemplo es perferto y muy util… aver listillos, como cojones os quedais con el «nombre solo» (sin la extension) de un archivo? por ejemplo $HOME/Escritorio/pruebas/imp.txt quedarte solo con «imp»
    ES IMPOSIBLE…. algun listillo dira: con basename, si le metes basename $HOME/Escritorio/pruebas/imp.txt .txt te lo quita… Hombre claro que lo quita, pero le tienes que decir: quita .txt de forma explicita, y si no sabes si es .txt o .sh o que extension? no se puede…
    asi que es un ejemplo necesario, el saber tratar las cadenas a ese bajo nivel de trocearlas tipo python.

    Conclusion: basename y dirname son inutiles cuando quieres tener por ejemplo el nombre de todos los archivos de un directorio pero sin extension.

  8. A mí también me parece muy útil el script, en absoluto has perdido el tiempo. De hecho, he creado una entrada en mi blog con el script por si le puede ayudar a alguien más.

  9. Me alegro de que lo encuentres útil!! 🙂

  10. Pues a mi tambien me parece muy útil, le he estado dando la vuelta a extraer los nombres y aunque con otros comandos tambien funciona, con basename y dirname no me fué, así que gracias por mi parte.

  11. Aguztíñ IV

    Una duda… he buscado sin éxito qué significa [^.] en tu código, incluso lo he usado [.^] dando resultados diferentes pero no logro entender qué significa y qué hace exactamente, ojalá puedas resolver mi duda, saludos cordiales.

  12. cesarheide

    El código termina siendo totalmente inútil cuando cuando se puede hacer con menos lineas de código.


    filename=$(basename "$NEWFILE".tex)
    extension="${filename##*.}"
    filename="${filename%.*}"
    dir=`dirname "$NEWFILE".tex`
    echo $dir
    echo $filename
    echo $extension

    «gutenn» a ver si aprendemos a respetar y mantenemos la boca cerrada cuando no sabemos.

  13. Tu script me sirvió muchísimo, es exactamente lo que necesitaba, gracias!

  14. Hola gracias por el aporte!!

  15. Simón Martínez

    La línea
    for RutaCompleta in $1
    debería ser
    for RutaCompleta in «$1»
    para que funcione bien con nombres con espacios.

  16. Efectivamente Simón, bien visto.

  17. Hi blogger, i must say you have hi quality articles here. Your page should go viral.
    You need initial traffic boost only. How to get it?

    Search for: Mertiso’s tips go viral

  18. I see you don’t monetize your page, don’t waste your traffic, you can earn extra cash every month because you’ve
    got high quality content. If you want to know how to make extra money,
    search for: Mertiso’s tips best adsense alternative

  19. I have noticed you don’t monetize your website, don’t waste your traffic, you can earn extra bucks every month.

    You can use the best adsense alternative for any type of website (they approve
    all websites), for more details simply search in gooogle: boorfe’s
    tips monetize your website

  20. I have read so many posts concerning the blogger lovers
    however this article is truly a good piece of
    writing, keep it up. http://www.xn--s39amm0p92s99lv1bd1n2bw64dp6a7z2alj3a.kr/

  21. Your point of view caught my eye and was very interesting. Thanks. I have a question for you. https://accounts.binance.com/bg/register-person?ref=V2H9AFPY

  22. I just wanted to thank you for the fast service. along with they look great. I received them a day earlier than expected. just like I will definitely continue to buy from this site. regardless I will recommend this site to my friends. Thanks!
    original louis vuittons outlet https://www.cheapreallouisvuitton.com/

  23. I just wanted to thank you for the fast service. or perhaps they look great. I received them a day earlier than expected. similar to the I will definitely continue to buy from this site. anyway I will recommend this site to my friends. Thanks!
    cheap louis vuitton bags https://www.bestlouisvuittonoutlet.com/

  24. I just wanted to thank you for the fast service. or simply they look great. I received them a day earlier than expected. such as I will definitely continue to buy from this site. you ultimately choose I will recommend this site to my friends. Thanks!
    cheap retro jordans https://www.realcheapretrojordanshoes.com/

  25. I just wanted to thank you for the fast service. quite possibly they look great. I received them a day earlier than expected. such I will definitely continue to buy from this site. either way I will recommend this site to my friends. Thanks!
    cheap real jordans https://www.cheaprealjordan.com/

  26. I am sorting out relevant information about gate io recently, and I saw your article, and your creative ideas are of great help to me. However, I have doubts about some creative issues, can you answer them for me? I will continue to pay attention to your reply. Thanks.

Menciones/Notificaciones

  1. Descomponer una ruta en directorios, nombre de archivo y extensión, en bash - [...] Descomponer una ruta en directorios, nombre de archivo y extensión, en bash www.archivoslog.es/2010/09/descomponer-una-ruta-en-direct...  por alwaro_1 hace 2 segundos [...]