scripts script que manejo español ejemplos ejecutar comandos comando cadenas string bash filenames

string - script - ¿Cómo elimino el sufijo de archivo y la parte de la ruta de acceso de una cadena de ruta en Bash?



scripts bash ejemplos (13)

Además de la sintaxis conforme con POSIX utilizada en esta respuesta ,

$ x="/foo/fizzbuzz.bar.quux" $ y=(`basename ${x%%.*}`) $ echo $y fizzbuzz

como en

basename string [suffix]

El basename GNU soporta otra sintaxis:

basename /foo/fizzbuzz.bar .bar

Con el mismo resultado. La diferencia y la ventaja es que -s implica -a , que admite múltiples argumentos:

basename -s .bar /foo/fizzbuzz.bar

Esto incluso se puede hacer seguro para el nombre de archivo separando la salida con bytes NUL usando la opción -z , por ejemplo, para estos archivos que contienen espacios en blanco, líneas nuevas y caracteres globales (citados por ls ):

$ basename -s .bar /foo/fizzbuzz.bar /baz/foobar.bar fizzbuzz foobar

Leyendo en una matriz:

$ ls has* ''has''$''/n''''newline.bar'' ''has space.bar'' ''has*.bar''

readarray -d requiere Bash 4.4 o posterior. Para versiones anteriores, tenemos que hacer un bucle:

$ readarray -d $''/0'' arr < <(basename -zs .bar has*) $ declare -p arr declare -a arr=([0]=$''has/nnewline'' [1]="has space" [2]="has*")

Dada una ruta de archivo de cadena como /foo/fizzbuzz.bar , ¿cómo usaría bash para extraer solo la parte de fizzbuzz de dicha cadena?


Aquí se explica cómo hacerlo con los operadores # y% en Bash.

$ x="/foo/fizzbuzz.bar" $ y=${x%.bar} $ echo ${y##*/} fizzbuzz

${x%.bar} también podría ser ${x%.*} para eliminar todo después de un punto o ${x%%.*} para eliminar todo después del primer punto.

Ejemplo:

$ x="/foo/fizzbuzz.bar.quux" $ y=${x%.*} $ echo $y /foo/fizzbuzz.bar $ y=${x%%.*} $ echo $y /foo/fizzbuzz

La documentación se puede encontrar en el manual de Bash . Busque la sección de coincidencia de la parte final de ${parameter%word} y ${parameter%%word} .


Bash puro, hecho en dos operaciones separadas:

  1. Eliminar la ruta de una cadena de ruta:

    path=/foo/bar/bim/baz/file.gif file=${path##*/} #$file is now ''file.gif''

  2. Eliminar la extensión de una cadena de ruta:

    base=${file%.*} #${base} is now ''file''.


Combinando la respuesta con la mejor calificación con la segunda respuesta con la mejor calificación para obtener el nombre de archivo sin la ruta completa:

while IFS= read -r -d '''' fname; do arr+=("$fname"); done < <(basename -zs .bar has*)


Cuidado con la solución perl sugerida: elimina cualquier cosa después del primer punto.

$ echo some.file.with.dots | perl -pe ''s//..*$//;s{^.*/}{}'' some

Si quieres hacerlo con perl, esto funciona:

$ echo some.file.with.dots | perl -pe ''s/(.*)/..*$/$1/;s{^.*/}{}'' some.file.with

Pero si está utilizando Bash, las soluciones con y=${x%.*} (O basename "$x" .ext si conoce la extensión) son mucho más simples.


El nombre base hace eso, elimina la ruta. También eliminará el sufijo si se da y si coincide con el sufijo del archivo, pero necesitará saber el sufijo para dar al comando. De lo contrario, puede usar mv y averiguar cuál debería ser el nuevo nombre de alguna otra manera.


El uso de basename supone que sabes cuál es la extensión del archivo, ¿no es así?

Y creo que las diversas sugerencias de expresiones regulares no hacen frente a un nombre de archivo que contiene más de uno "."

Lo siguiente parece hacer frente a los puntos dobles. Ah, y los nombres de archivo que contienen una "/" (solo para patadas)

Parafraseando a Pascal: "Lo siento, este script es tan largo. No tuve tiempo de hacerlo más corto"

#!/usr/bin/perl $fullname = $ARGV[0]; ($path,$name) = $fullname =~ /^(.*[^//]//)*(.*)$/; ($basename,$extension) = $name =~ /^(.*)(/.[^.]*)$/; print $basename . "/n";


Las funciones basename y dirname son las siguientes:

mystring=/foo/fizzbuzz.bar echo basename: $(basename $mystring) echo basename + remove .bar: $(basename $mystring .bar) echo dirname: $(dirname $mystring)

Tiene salida:

basename: fizzbuzz.bar basename + remove .bar: fizzbuzz dirname: /foo


Puro camino de bash:

~$ x="/foo/bar/fizzbuzz.bar.quux.zoom"; ~$ y=${x///*///}; ~$ echo ${y/.*/}; fizzbuzz

Esta funcionalidad se explica en man bash en "Expansión de parámetros". Abundan las formas no bash: awk, perl, sed y así sucesivamente.

EDITAR: funciona con puntos en los sufijos de archivos y no necesita conocer el sufijo (extensión), pero no funciona con puntos en el nombre en sí.


Si no puedes usar el nombre base como se sugiere en otras publicaciones, siempre puedes usar sed. Aquí hay un ejemplo (feo). No es el mejor, pero funciona extrayendo la cadena deseada y reemplazando la entrada con la cadena deseada.

echo ''/foo/fizzbuzz.bar'' | sed ''s|.*///([^/.]*/)/(/..*/)$|/1|g''

Lo que te dará la salida.

Fizzbuzz


Usando basename usé lo siguiente para lograr esto:

for file in *; do ext=${file##*.} fname=`basename $file $ext` # Do things with $fname done;

Esto no requiere un conocimiento a priori de la extensión de archivo y funciona incluso cuando tiene un nombre de archivo que tiene puntos en su nombre de archivo (delante de su extensión); Sin embargo, sí requiere el basename del programa, pero esto es parte de los coreutils de GNU, por lo que debería enviarse con cualquier distro.


mira el comando basename:

NAME=`basename /foo/fizzbuzz.bar .bar`


perl -pe ''s//..*$//;s{^.*/}{}''