Pregunta Extrae el nombre de archivo y la extensión en Bash


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

La mejor solución que encontré hasta ahora es:

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

Esto es incorrecto 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 iniciar un intérprete de Python solo para esto, si es posible.

Alguna mejor idea?


1614
2018-06-08 14:00


origen


Respuestas:


Primero, obtenga el nombre del archivo sin la ruta:

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

Alternativamente, puede enfocarse en el último '/' de la ruta en lugar del '.' que debería funcionar incluso si tiene extensiones de archivo impredecibles:

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

2806
2018-06-08 14:05



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

Para más detalles, ver ampliación del parámetro de shell en el manual de Bash.


502
2018-06-08 14:05



Por lo general, ya conoce la extensión, por lo que es posible que desee utilizar:

basename filename .extension

por ejemplo:

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

y obtenemos

filename

279
2017-10-19 10:56



Puedes usar la magia de las variables POSIX:

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

Hay una advertencia en eso si su nombre de archivo era de la forma ./somefile.tar.gz entonces echo ${FILENAME%%.*} eliminaría avariciosamente la coincidencia más larga con la . y tendrías la cadena vacía

(Puede solucionarlo con una variable temporal:

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

)


Esta 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

125
2018-02-05 09:09



Eso no parece funcionar si el archivo no tiene extensión, o no tiene nombre de archivo. Esto es lo que estoy usando; solo usa builtins y maneja más (pero no todos) nombres de archivos 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 = ""
/casa/:
    dir = "/ home / me /"
    base = ""
    ext = ""
/ home / me / file:
    dir = "/ home / me /"
    base = "archivo"
    ext = ""
/home/me/file.tar:
    dir = "/ home / me /"
    base = "archivo"
    ext = "tar"
/home/me/file.tar.gz:
    dir = "/ home / me /"
    base = "archivo.tar"
    ext = "gz"
/home/me/.hidden:
    dir = "/ home / me /"
    base = ".hidden"
    ext = ""
/home/me/.hidden.tar:
    dir = "/ home / me /"
    base = ".hidden"
    ext = "tar"
/casa/..:
    dir = "/ home / me /"
    base = ".."
    ext = ""
.:
    dir = ""
    base = "."
    ext = ""

65
2017-09-10 05:17



Puedes usar basename.

Ejemplo:

$ basename foo-bar.tar.gz .tar.gz
foo-bar

Necesitas proporcionar un nombre de base con la extensión que se eliminará, sin embargo, si siempre estás ejecutando tar con -z entonces sabes que la extensión será .tar.gz.

Esto debería hacer lo que quieras:

tar -zxvf $1
cd $(basename $1 .tar.gz)

40
2018-02-05 08:50



Mellen escribe en un comentario en una publicación de blog:

Usando Bash, también hay ${file%.*} para obtener el nombre de archivo sin la extensión y ${file##*.} para obtener la extensión solo Es decir,

file="thisfile.txt"
echo "filename: ${file%.*}"
echo "extension: ${file##*.}"

Productos:

filename: thisfile
extension: txt

24
2017-07-21 10:24