Como obter apenas o nome do arquivo usando sed

15

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

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

Mas também obtenho o caminho /root/video.mp4 e quero apenas video.mp4 .

    
por Shixons 04.08.2012 / 06:57

4 respostas

24

basename do coreutils do GNU pode ajudá-lo a fazer este trabalho:

$ basename /root/video.mp4
video.mp4

Se você já conhece a extensão do arquivo, pode invocar 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
    
por 04.08.2012 / 09:05
8

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

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

    
por 04.08.2012 / 08:32
5

Use qualquer 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 na sua instrução \(.*\.\) corresponde à string desde o início até o ponto ( /root/video. ) e, em seguida, você adiciona manualmente .mp4 , que é o mesmo da string original. Você deve usar s=.*\([^/]*\)== .

Atualização: (a primeira é corrigida 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=\([^/]*\)\.[^./]*$=.new_ext=')"

out_file="$(echo $in_file | awk -F"/" '{ gsub (/\.[^/.]*$/,".new_ext",$NF);print $NF }'
    
por 04.08.2012 / 07:45
4

Um dos fundamentos do uso do 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 sed.

Antes de continuar, é sempre útil saber qual versão do sed é o alvo. Estou assumindo o BSD (como fornecido com o OSX).

Em primeiro lugar, o padrão proposto na pergunta original não funciona porque ele captura tudo, desde o início da string de entrada até o último ponto. Sem âncoras, esta pesquisa irá engolir tudo da esquerda para a direita. O padrão de correspondência "/ 1", portanto, é tudo até e incluindo o último ponto. Até 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 (lidaremos com a extensão mais tarde):

out_file="$(echo $in_file | sed 's/^\(\/.*\/\)*.*//')"

A pesquisa corresponde ao início da string. Ele corresponde a um padrão de "/.*" zero ou mais vezes e exclui tudo depois. Nós imprimimos os padrões combinados com "\ 1". Nós não estamos buscando globalmente; estamos pesquisando desde o começo da string, especificando a âncora.

Temos mais clareza ativando a opção "-E", para que não seja necessário escapar dos parênteses:

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*.*//')"

Então agora temos a parte à esquerda. Vamos adicionar a parte à direita. Note que precisamos manter a parte esquerda como um padrão, porque é assim que podemos especificar que ela aparece zero ou mais vezes. Tudo o que fazemos agora é adicionar um padrão para a parte à direita:

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)//')"

Apenas 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/^(\/.*\/)*(.*)\..*$//')"

O "$" no final é opcional.

Por fim, para adicionar a nova extensão que você acabou de revisar da seguinte forma:

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/.mp4/')"

Uma otimização adicional é tornar a primeira barra opcional opcional para lidar com caminhos relativos:

out_file="$(echo $in_file | sed -E 's/^([\/]?.*\/)*(.*)\..*$/.mp4/')"

Eu me deparei com essa pergunta sendo preguiçoso enquanto procurava por um padrão sed para substituir basename . Estou trabalhando em um sistema separado que não tem esse comando instalado.

    
por 14.10.2014 / 22:44

Tags