Respostas:
basename
do coreUtil GNU pode ajudá-lo a fazer este trabalho:
$ basename /root/video.mp4
video.mp4
Se você já conhece a extensão do arquivo, pode chamar basename
usando a sintaxe basename NAME [SUFFIX]
para removê-lo:
$ basename /root/video.mp4 .mp4
video
Ou outra opção seria cortar tudo após o último ponto usando sed
:
$ basename /root/video.old.mp4 | sed 's/\.[^.]*$//'
video.old
Use uma das seguintes maneiras:
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 }')"
ps. Você obtém a mesma string porque em sua declaração\(.*\.\)
corresponde à string desde o início até o ponto ( /root/video.
) e, em seguida, adiciona manualmente .mp4
o mesmo valor da string original. Você deve usar em seu s=.*\([^/]*\)=\1=
lugar.
Atualização: (o primeiro foi corrigido agora)
Para obter o único nome de arquivo sem extensão, você pode:
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
e awk
. Fixo. Obrigado.
Um dos fundamentos do uso de regex é que os padrões são gananciosos por natureza ao especificar o curinga. Embora a resposta proposta por @uloBasEI seja certamente uma resposta funcional, também requer o uso do comando basename. A pergunta original do @Shixons solicita uma solução usando apenas o sed.
Antes de continuar, é sempre útil saber qual versão do sed é o alvo. Estou assumindo BSD (como fornecido com o OSX).
Primeiro, o padrão proposto na pergunta original não funciona porque captura tudo desde o início da sequência de entrada até o último ponto e inclusive. Sem âncoras, essa pesquisa absorverá tudo da esquerda para a direita. O padrão "/ 1" correspondido, portanto, inclui tudo, inclusive o último ponto. Mesmo um nome de arquivo com vários pontos será engolido inteiro. Não é o resultado desejado.
O primeiro passo é estabelecer uma estratégia para identificar padrões. Aqui, você gostaria de se livrar de tudo à esquerda do nome do arquivo (trataremos da extensão posteriormente):
out_file="$(echo $in_file | sed 's/^\(\/.*\/\)*.*/\1/')"
A pesquisa corresponde desde o início da string. Corresponde a um padrão de "/.*" zero ou mais vezes e exclui tudo depois. Imprimimos os padrões correspondentes com "\ 1". Não estamos pesquisando globalmente; estamos pesquisando desde o início da string especificando a âncora ^.
Temos maior clareza ao ativar a opção "-E" para que não tenhamos que escapar dos parênteses:
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*.*/\1/')"
Então agora temos a parte à esquerda. Vamos adicionar a peça à direita. Observe que precisamos manter a parte esquerda como padrão, pois é assim que podemos especificar que ela apareça zero ou mais vezes. Tudo o que fazemos agora é adicionar um padrão para a peça à direita:
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)/\2/')"
Somente imprimimos a segunda correspondência, descartando tudo, menos o nome do arquivo. Mas ainda precisamos remover a extensão do nome do arquivo.
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2/')"
O "$" no final é opcional.
Por fim, para adicionar a nova extensão, basta revisar da seguinte maneira:
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2.mp4/')"
Uma otimização adicional é tornar a primeira barra opcional opcional para lidar com caminhos relativos:
out_file="$(echo $in_file | sed -E 's/^([\/]?.*\/)*(.*)\..*$/\2.mp4/')"
Me deparei com essa questão por ser preguiçoso enquanto procurava um padrão sed para substituir o nome da base . Estou trabalhando em um sistema despojado que não possui esse comando instalado.
sed 's/\.[^.]*$//'
o que tiver, falhará em (oculto).filename
e.
e..
diretórios