Acabei usando este porque era o mais flexível e havia algumas outras coisas semelhantes que eu queria fazer, bem como isso.
Lawrence Johnston
Essa é provavelmente a mais flexível de todas as respostas postadas, mas acho que as respostas que sugerem os comandos basename e dirname também merecem atenção. Eles podem ser apenas o truque se você não precisar de nenhuma outra correspondência de padrões sofisticados.
mgadda
7
Como isso se chama $ {x% .bar}? Eu gostaria de aprender mais sobre isso.
Manjericão
14
@ Basil: Expansão de parâmetros. Em um console, digite "man bash" e digite "/ parameter expansion"
Zan Lynx
11
Eu acho que a explicação 'bash man' faz sentido se você já sabe o que faz ou se tentou por si mesmo da maneira mais difícil. É quase tão ruim quanto a referência do git. Eu apenas pesquisaria no Google.
Provavelmente a mais simples de todas as soluções atualmente oferecidas ... embora eu usasse $ (...) em vez de reticulares.
Michael Johnson
6
Mais simples, mas acrescenta uma dependência (não uma enorme ou estranha, admito). Ele também precisa conhecer o sufixo.
Vinko Vrsalovic 24/09/08
E pode ser usado para remover qualquer coisa do final, basicamente faz apenas uma remoção de string do final.
Smar
2
O problema é o tempo atingido. Acabei de pesquisar a pergunta para esta discussão depois de assistir ao bash levar quase 5 minutos para processar 800 arquivos, usando basename. Usando o método regex acima, o tempo foi reduzido para cerca de 7 segundos. Embora essa resposta seja mais fácil de executar para o programador, o tempo atingido é demais. Imagine uma pasta com alguns milhares de arquivos nela! Eu tenho algumas dessas pastas.
Xizdaqrian
@xizdaqrian Isso é absolutamente falso. Este é um programa simples, que não deve demorar meio segundo para retornar. Acabei de executar o tempo find / home / me / dev -name "* .py" .py -exec basename {} \; e retirou a extensão e o diretório de 1500 arquivos em 1 segundo no total.
Laszlo Treszkai 12/12/19
40
Pure bash, realizado em duas operações separadas:
Remova o caminho de uma string de caminho:
path=/foo/bar/bim/baz/file.gif
file=${path##*/} #$file is now 'file.gif'
Usando o nome de base, usei o seguinte para conseguir isso:
for file in*;do
ext=${file##*.}
fname=`basename $file $ext`# Do things with $fnamedone;
Isso não requer conhecimento a priori da extensão do arquivo e funciona mesmo quando você tem um nome de arquivo com pontos no nome do arquivo (na frente da extensão); embora exija o programa basename, mas isso faz parte dos coreutils do GNU, portanto deve ser fornecido com qualquer distribuição.
Seria útil corrigir a citação aqui - talvez execute isso no shellcheck.net com mystring=$1o valor constante atual (que suprimirá vários avisos, garantindo que não contenha espaços / caracteres globos / etc) e resolva os problemas encontra?
Charles Duffy
Bem, fiz algumas alterações apropriadas para suportar aspas em $ mystring. Puxa isso foi há muito tempo atrás eu escrevi este :)
Jerub
Seria uma melhoria adicional para citar os resultados: echo "basename: $(basename "$mystring")"- dessa forma, se mystring='/foo/*'você não for *substituído por uma lista de arquivos no diretório atual após abasename conclusão.
Charles Duffy
6
Usar basenamesupõe que você saiba qual é a extensão do arquivo, não é?
E acredito que as várias sugestões de expressões regulares não lidam com um nome de arquivo que contém mais de um "."
O seguinte parece lidar com pontos duplos. Ah, e nomes de arquivos que contenham um "/" (apenas para brincadeiras)
Parafraseando Pascal, "Desculpe, este script é tão longo. Não tive tempo para reduzi-lo"
Isso pode até tornar o nome do arquivo seguro, separando a saída com bytes NUL usando a -zopção, por exemplo, para esses arquivos que contêm espaços em branco, novas linhas e caracteres glob (citados por ls):
$ ls has*'has'$'\n''newline.bar''has space.bar''has*.bar'
Se você não pode usar o nome da base como sugerido em outras postagens, sempre pode usar o sed. Aqui está um exemplo (feio). Não é o melhor, mas funciona extraindo a sequência desejada e substituindo a entrada pela sequência desejada.
echo '/foo/fizzbuzz.bar'| sed 's|.*\/\([^\.]*\)\(\..*\)$|\1|g'
Embora essa seja a resposta para a pergunta original, esse comando é útil quando tenho linhas de caminhos em um arquivo para extrair nomes de base e imprimi-los na tela.
Sangcheol Choi
2
Cuidado com a solução perl sugerida: ela remove qualquer coisa após o primeiro ponto.
$ echo some.file.with.dots | perl -pe 's/\..*$//;s{^.*/}{}'
some
Se você quiser fazer isso com perl, isso funciona:
O nome da base faz isso, remove o caminho. Ele também removerá o sufixo se for fornecido e se corresponder ao sufixo do arquivo, mas você precisará saber o sufixo a ser fornecido ao comando. Caso contrário, você pode usar mv e descobrir qual deve ser o novo nome de outra maneira.
Combinando a resposta com a melhor classificação com a segunda resposta com a melhor classificação para obter o nome do arquivo sem o caminho completo:
${parameter%word}
e${parameter%%word}
na seção correspondente à parte à direita.Respostas:
Veja como fazer isso com os operadores # e% no Bash.
${x%.bar}
Também pode ser${x%.*}
remover tudo após um ponto ou${x%%.*}
remover tudo após o primeiro ponto.Exemplo:
A documentação pode ser encontrada no manual do Bash . Procure
${parameter%word}
e${parameter%%word}
arraste a seção correspondente da parte.fonte
veja o comando basename:
fonte
Pure bash, realizado em duas operações separadas:
Remova o caminho de uma string de caminho:
Remova a extensão de uma cadeia de caminho:
fonte
Usando o nome de base, usei o seguinte para conseguir isso:
Isso não requer conhecimento a priori da extensão do arquivo e funciona mesmo quando você tem um nome de arquivo com pontos no nome do arquivo (na frente da extensão); embora exija o programa
basename
, mas isso faz parte dos coreutils do GNU, portanto deve ser fornecido com qualquer distribuição.fonte
fname=`basename $file .$ext`
Maneira pura da festança:
Esta funcionalidade é explicada no man bash em "Expansão de parâmetros". Maneiras não bash abundam: awk, perl, sed e assim por diante.
EDIT: trabalha com pontos nos sufixos do arquivo e não precisa saber o sufixo (extensão), mas não funciona com pontos no próprio nome .
fonte
As funções basename e dirname são o que você procura:
Possui saída:
fonte
mystring=$1
o valor constante atual (que suprimirá vários avisos, garantindo que não contenha espaços / caracteres globos / etc) e resolva os problemas encontra?echo "basename: $(basename "$mystring")"
- dessa forma, semystring='/foo/*'
você não for*
substituído por uma lista de arquivos no diretório atual após abasename
conclusão.Usar
basename
supõe que você saiba qual é a extensão do arquivo, não é?E acredito que as várias sugestões de expressões regulares não lidam com um nome de arquivo que contém mais de um "."
O seguinte parece lidar com pontos duplos. Ah, e nomes de arquivos que contenham um "/" (apenas para brincadeiras)
Parafraseando Pascal, "Desculpe, este script é tão longo. Não tive tempo para reduzi-lo"
fonte
Além da sintaxe em conformidade com POSIX usada nesta resposta ,
como em
O GNU
basename
suporta outra sintaxe:com o mesmo resultado. A diferença e vantagem é que isso
-s
implica-a
, que suporta vários argumentos:Isso pode até tornar o nome do arquivo seguro, separando a saída com bytes NUL usando a
-z
opção, por exemplo, para esses arquivos que contêm espaços em branco, novas linhas e caracteres glob (citados porls
):Lendo em uma matriz:
readarray -d
requer o Bash 4.4 ou mais recente. Para versões mais antigas, temos que fazer um loop:fonte
fonte
Se você não pode usar o nome da base como sugerido em outras postagens, sempre pode usar o sed. Aqui está um exemplo (feio). Não é o melhor, mas funciona extraindo a sequência desejada e substituindo a entrada pela sequência desejada.
O que lhe dará a saída
fonte
Cuidado com a solução perl sugerida: ela remove qualquer coisa após o primeiro ponto.
Se você quiser fazer isso com perl, isso funciona:
Mas se você estiver usando o Bash, as soluções com
y=${x%.*}
(oubasename "$x" .ext
se você conhece a extensão) são muito mais simples.fonte
O nome da base faz isso, remove o caminho. Ele também removerá o sufixo se for fornecido e se corresponder ao sufixo do arquivo, mas você precisará saber o sufixo a ser fornecido ao comando. Caso contrário, você pode usar mv e descobrir qual deve ser o novo nome de outra maneira.
fonte
Combinando a resposta com a melhor classificação com a segunda resposta com a melhor classificação para obter o nome do arquivo sem o caminho completo:
fonte