Extraer el nombre de archivo y la extensión en Bash

bash string filenames


Quiero obtener el nombre del archivo (sin extensión)y la extensión por separado.

La mejor solución que he encontrado hasta ahora es:

NAME=`echo "$FILE" | cut -d'.' -f1`
EXTENSION=`echo "$FILE" | cut -d'.' -f2`

Esto está mal porque no funciona si el nombre del archivo contiene múltiples . caracteres. Si, digamos, tengo a.b.js , considerará a y b.js , en lugar de a.b y js .

Se puede hacer fácilmente en Python con

file, ext = os.path.splitext(path)

pero preferiría no contratar a un intérprete de Python sólo para esto,si es posible.

¿Alguna idea mejor?




Answer 1 Petesh


Primero,consigue el nombre del archivo sin la ruta:

filename=$(basename -- "$fullfile")
extension="${filename##*.}"
filename="${filename%.*}"

Alternativamente,puedes enfocarte en el último '/' de la ruta en lugar del '.' que debería funcionar aunque tengas extensiones de archivo impredecibles:

filename="${fullfile##*/}"

Puede que quieras comprobar la documentación:




Answer 2 Juliano


~% FILE="example.tar.gz"

~% echo "${FILE%%.*}"
example

~% echo "${FILE%.*}"
example.tar

~% echo "${FILE#*.}"
tar.gz

~% echo "${FILE##*.}"
gz

Para obtener más detalles, consulte la expansión de parámetros de shell en el manual de Bash.




Answer 3 Tomi Po


Por lo general,ya conoces la extensión,así que tal vez quieras usarla:

basename filename .extension

por ejemplo:

basename /path/to/dir/filename.txt .txt

y tenemos

filename



Answer 4 sotapme


Puedes usar la magia de la expansión del parámetro POSIX:

bash-3.2$ FILENAME=somefile.tar.gz
bash-3.2$ echo "${FILENAME%%.*}"
somefile
bash-3.2$ echo "${FILENAME%.*}"
somefile.tar

Hay una advertencia de que si su nombre de archivo tenía la forma ./somefile.tar.gz , echo ${FILENAME%%.*} Eliminaría con avidez la coincidencia más larga para . y tendrías la cadena vacía.

(Puede solucionar eso con una variable temporal:

FULL_FILENAME=$FILENAME
FILENAME=${FULL_FILENAME##*/}
echo ${FILENAME%%.*}

)


Este sitio explica más.

${variable%pattern}
  Trim the shortest match from the end
${variable##pattern}
  Trim the longest match from the beginning
${variable%%pattern}
  Trim the longest match from the end
${variable#pattern}
  Trim the shortest match from the beginning



Answer 5 Doctor J


Eso no parece funcionar si el archivo no tiene extensión,o no tiene nombre de archivo.Esto es lo que estoy usando;sólo usa builtins y maneja más (pero no todos)nombres de archivo patológicos.

#!/bin/bash
for fullpath in "$@"
do
    filename="${fullpath##*/}"                      # Strip longest match of */ from start
    dir="${fullpath:0:${#fullpath} - ${#filename}}" # Substring from 0 thru pos of filename
    base="${filename%.[^.]*}"                       # Strip shortest match of . plus at least one non-dot char from end
    ext="${filename:${#base} + 1}"                  # Substring from len of base thru end
    if [[ -z "$base" && -n "$ext" ]]; then          # If we have an extension and no base, it's really the base
        base=".$ext"
        ext=""
    fi

    echo -e "$fullpath:\n\tdir  = \"$dir\"\n\tbase = \"$base\"\n\text  = \"$ext\""
done

Y aquí hay algunos casos de prueba:

$ basename-and-extension.sh / /home/me/ /home/me/file /home/me/file.tar /home/me/file.tar.gz /home/me/.hidden /home/me/.hidden.tar /home/me/.. .
/:
    dir  = "/"
    base = ""
    ext  = ""
/home/me/:
    dir  = "/home/me/"
    base = ""
    ext  = ""
/home/me/file:
    dir  = "/home/me/"
    base = "file"
    ext  = ""
/home/me/file.tar:
    dir  = "/home/me/"
    base = "file"
    ext  = "tar"
/home/me/file.tar.gz:
    dir  = "/home/me/"
    base = "file.tar"
    ext  = "gz"
/home/me/.hidden:
    dir  = "/home/me/"
    base = ".hidden"
    ext  = ""
/home/me/.hidden.tar:
    dir  = "/home/me/"
    base = ".hidden"
    ext  = "tar"
/home/me/..:
    dir  = "/home/me/"
    base = ".."
    ext  = ""
.:
    dir  = ""
    base = "."
    ext  = ""