Como obter apenas o nome do arquivo usando sed

17

Como posso obter apenas o nome do arquivo usando sed? Eu tenho isso

out_file=$(echo $in_file|sed "s/\(.*\.\).*/\1mp4/g")

Mas eu também pego o caminho /root/video.mp4e quero apenas video.mp4.

Shixons
fonte

Respostas:

26

basenamedo 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 basenameusando 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
uloBasEI
fonte
3
Se usar sed 's/\.[^.]*$//'o que tiver, falhará em (oculto) .filenamee. e ..diretórios
Peter.O
9

A solução mais fácil é remover tudo até a última aparição de /:

echo /root/video.mp4 | sed 's/.*\///'

margarida
fonte
5

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 .mp4o 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 }'
pressa
fonte
Mas com qualquer um desses métodos, obtenho o nome do arquivo com o formato e preciso obter apenas o nome do arquivo e colocar um novo formato manualmente.
Shixons 04/04/12
Ah, isso faz sentido. Eu atualizei minha resposta.
apressar
@rush: haverá casos extremos, por exemplo, para um arquivo chamado my.file.tar.gz.
donothingsuccessfully
@donothingsuccessfully houve um símbolo de ponto ausente no último sede awk. Fixo. Obrigado.
apressar
4

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.

markeissler
fonte