Obter o último nome de arquivo / diretório em um argumento de caminho de arquivo no Bash

228

Estou tentando escrever um gancho pós-confirmação para o SVN, hospedado em nosso servidor de desenvolvimento. Meu objetivo é tentar fazer check-out automático de uma cópia do projeto confirmado no diretório em que ele está hospedado no servidor. No entanto, preciso poder ler apenas o último diretório da cadeia de diretório passada para o script para fazer checkout no mesmo subdiretório em que nossos projetos estão hospedados.

Por exemplo, se eu fizer um SVN confirmar o projeto "exemplo", meu script obterá "/ usr / local / svn / repos / example" como seu primeiro argumento. Eu preciso tirar apenas "exemplo" do final da string e concatená-la com outra string para que eu possa fazer checkout em "/ server / root / example" e ver as alterações ao vivo imediatamente.

TJ L
fonte

Respostas:

344

basename remove o prefixo do diretório de um caminho:

$ basename /usr/local/svn/repos/example
example
$ echo "/server/root/$(basename /usr/local/svn/repos/example)"
/server/root/example
sth
fonte
2
Definitivamente, basename é o que estou procurando. Como pode obter o nome de base de um argumento armazenado em uma variável? Por exemploSUBDIR="/path/to/whatever/$(basename $1)"
TJ L
5
@ tj111: Parece que não é $1, ou $1está vazio
sth
infelizmente, se você quebrar comandos, basename não é uma boa ideia. apenas algo a ter em mente
dtc
98

A abordagem a seguir pode ser usada para obter qualquer caminho de um nome de caminho:

some_path=a/b/c
echo $(basename $some_path)
echo $(basename $(dirname $some_path))
echo $(basename $(dirname $(dirname $some_path)))

Resultado:

c
b
a
Jingguo Yao
fonte
1
não trabalho com caminhos que têm espaços ... você pode superar isso com citações ... que de alguma forma funcionaecho "$(basename "$(dirname "$pathname")")"
Ray Foss
75

O Bash pode obter a última parte de um caminho sem precisar chamar o externo basename:

subdir="/path/to/whatever/${1##*/}"
Pausado até novo aviso.
fonte
2
No meu Mac, o uso da notação de substring é mais do que a ordem de magnitude mais rápido que o dirname / basename para o caso em que você está fazendo algo trivial para cada um dos milhares de arquivos.
George George
1
d=/home/me/somefolder;subdir="/$d/${1##*/}"Acabei com algo como //home/me/somefolder//o $ d, na verdade, vem de um loop. for d in $(find $SOMEFOLDER -maxdepth 1 -type d);Usando subdir=$(basename $d)funciona como esperado.
Buttle Butkus
1
@ButtleButkus: Você deve usar em whilevez de foriterar sobre a saída de find( find -print0 | xargs -0é melhor) ou usar globbing: for d in $SOMEFOLDER/*/(a barra final funciona como -type d- você pode usar **no Bash 4 para recursão, se quiser shopt -s globstar, mas a mensagem "Lista de argumentos muito longa" é possível). Observe que a ${1}parte do comando representa o primeiro argumento de um script ou função. Você pode precisar usar ${d##*/}alguma outra variável ou especificação de argumento ou certificar-se de que um argumento esteja sendo passado$1
Pausado até novo aviso.
2
@DennisWilliamson Muito obrigado por compartilhar . Para qualquer futuro leitor que começar a se perguntar por que não está funcionando, ou eu sou o único idiota por aqui ? A resposta acima assume que $1contém the path from which last component is to be taken out. Eu perdi essa parte. Meu caso de uso: target_path='/home/user/dir1/dir2/dir3/'; target_path="${target_path%/}"; last_component=${target_path##*/}; echo $last_component- Works 😉
Vinay Vissh 13/04/19
2
Veja aqui uma explicação de como e por que ${1##*/} funciona: unix.stackexchange.com/a/171786/15070
Matthew