Respuestas:
basename
de GNU coreutils puede ayudarlo a hacer este trabajo:
$ basename /root/video.mp4
video.mp4
Si ya conoce la extensión del archivo, puede invocar basename
usando la sintaxis basename NAME [SUFFIX]
para eliminarlo:
$ basename /root/video.mp4 .mp4
video
O otra opción sería cortar todo después del último punto usando sed
:
$ basename /root/video.old.mp4 | sed 's/\.[^.]*$//'
video.old
Utilice cualquiera de las siguientes formas:
out_file="${in_file##*/}"
out_file="$(basename $in_file)"
out_file="$(echo $in_file | sed 's=.*/==')"
out_file="$(echo $in_file | awk -F"/" '{ print $NF }')"
PD. Obtiene la misma cadena porque en su declaración \(.*\.\)
coincide con la cadena desde el principio hasta el punto ( /root/video.
) y luego agrega manualmente lo .mp4
que es lo mismo que en su cadena original. Deberías usar s=.*\([^/]*\)=\1=
en su lugar.
Actualización: (El primero está arreglado ahora)
Para obtener el único nombre de archivo sin extensión, puede:
out_file="$(echo $in_file | sed 's=.*/==;s/\.[^.]*$/.new_ext/')"
out_file="$(echo $in_file | sed 's=\([^/]*\)\.[^./]*$=\1.new_ext=')"
out_file="$(echo $in_file | awk -F"/" '{ gsub (/\.[^/.]*$/,".new_ext",$NF);print $NF }'
my.file.tar.gz
.
sed
y awk
. Fijo. Gracias.
Uno de los fundamentos del uso de expresiones regulares es que los patrones son codiciosos por naturaleza al especificar el comodín. Si bien la respuesta propuesta por @uloBasEI es ciertamente una respuesta funcional, también requiere el uso del comando basename. La pregunta original de @Shixons solicita una solución utilizando solo sed.
Antes de continuar, siempre es útil saber qué versión de sed es el objetivo. Asumo BSD (como se envía con OSX).
En primer lugar, el patrón propuesto en la pregunta original no funciona porque captura todo desde el comienzo de la cadena de entrada hasta el último punto, incluido el mismo. Sin anclajes, esta búsqueda se tragará todo de izquierda a derecha. El patrón coincidente "/ 1", por lo tanto, es todo hasta e incluyendo el último punto. Incluso un nombre de archivo con múltiples puntos se tragará entero. No es el resultado deseado en absoluto.
El primer paso es establecer una estrategia para identificar patrones. Aquí, le gustaría deshacerse de todo a la izquierda del nombre del archivo (trataremos la extensión más adelante):
out_file="$(echo $in_file | sed 's/^\(\/.*\/\)*.*/\1/')"
La búsqueda coincide desde el principio de la cadena. Coincide con un patrón de "/.*" cero o más veces y elimina todo después. Imprimimos los patrones coincidentes con "\ 1". No estamos buscando a nivel mundial; estamos buscando desde el principio de la cadena especificando el ancla ^.
Obtenemos una mejor claridad al habilitar la opción "-E" para no tener que escapar de los paréntesis:
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*.*/\1/')"
Entonces ahora tenemos la parte de la izquierda. Agreguemos la parte de la derecha. Tenga en cuenta que debemos mantener la parte izquierda como patrón porque así es como podemos especificar que aparezca cero o más veces. Todo lo que hacemos ahora es agregar un patrón para la parte de la derecha:
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)/\2/')"
Solo imprimimos la segunda coincidencia, descartando todo menos el nombre del archivo. Pero aún necesitamos eliminar la extensión del nombre de archivo.
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2/')"
El "$" al final es opcional.
Finalmente, para agregar la nueva extensión, simplemente revisa así:
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2.mp4/')"
Una optimización adicional es hacer que la primera barra diagonal sea opcional para manejar rutas relativas:
out_file="$(echo $in_file | sed -E 's/^([\/]?.*\/)*(.*)\..*$/\2.mp4/')"
Encontré esta pregunta siendo flojo mientras buscaba un patrón sed para reemplazar el nombre base . Estoy trabajando en un sistema despojado que no tiene ese comando instalado.
sed 's/\.[^.]*$//'
que usted tiene, se producirá un error de (oculto).filename
y.
y..
directorios