Encontre o caminho absoluto de um script

10

Em um script, entro no $0possível caminho relativo para ele. Para convertê-lo em absoluto, encontrei esta solução que não entendo:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

Meu problema é a mágica dentro de ${0%/*}e ${0##*/}. Parece que o primeiro extrai o nome do diretório e o último extrai o nome do arquivo, apenas não entendo como.

maaartinus
fonte
2
Isso usa expansão de parâmetro, mas não funcionou para mim. Se seu script for usado apenas no Linux, você poderá usar readlink -f $0o caminho canônico.
Shawn J. Goff
1
@ Shawn: um grande voto de comentário porque você introduziu o pensamento correto: "Isso usa expansão de parâmetro, mas não funcionou para mim". O dirnameutilitário é útil aqui.
D4RIO
mywiki.wooledge.org/BashFAQ/028 e cyberciti.biz/faq/… dizem que BASH_SOURCEé melhor do que $0, pois $0fornece o comando digitado pelo usuário, que pode não ser o script em execução no momento.
Joel Purra

Respostas:

8

Definições:

${string%substring} exclui a correspondência mais curta de $substringdo final de $string.

${string##substring}exclui a correspondência mais longa de $substringdesde o início de $string.

Seu exemplo:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

${0%/*} exclui tudo após a última barra, fornecendo o nome do diretório do script (que pode ser um caminho relativo).

${0##*/} exclui tudo até a última barra, fornecendo apenas o nome do script.

Portanto, esse comando muda para o diretório do script e concatena o diretório de trabalho atual (fornecido por $PWD) e o nome do script, fornecendo o caminho absoluto.

Para ver o que está acontecendo, tente:

echo ${0%/*}
echo ${0##*/}
dogbane
fonte
Adicione aspas duplas em torno de todas as expansões variáveis ​​para lidar com (quase todos) os nomes de arquivos que contêm caracteres especiais do shell.
Gilles 'SO- stop be evil'
10

Shawn teve a solução mais simples: readlink -f $0. Se você quiser ter certeza absoluta de lidar com nomes de arquivos estranhos, use:

absolute_path_x="$(readlink -fn -- "$0"; echo x)"
absolute_path="${absolute_path_x%x}"

Documentação

l0b0
fonte
1
É bom ver as novas linhas finais tratadas corretamente. Infelizmente readlink -fné específico para Linux, NetBSD e OpenBSD.
Gilles 'SO- stop be evil'
4

Aqui está uma maneira mais segura e legível de fazer este trabalho:

abspath=$(unset CDPATH && cd "$(dirname "$0")" && echo $PWD/$(basename "$0"))

Notas:

  • Se $0for um nome de arquivo simples, sem caminho anterior, o script original falhará, mas o fornecido aqui funcionará. (Não é um problema, $0mas pode estar em outros aplicativos.)
  • Qualquer uma das abordagens falhará se o caminho para o arquivo não existir realmente. (Não é um problema $0, mas pode estar em outros aplicativos.)
  • O unseté essencial se seu usuário pode ter CDPATHdefinido.
  • Diferentemente de readlink -fou realpath, isso funcionará em versões não Linux do Unix (por exemplo, Mac OS X).
Matthias Fripp
fonte
2

Se você deseja aprender a expansão de parâmetros do shell, pode lê-lo aqui , mas a expansão nem sempre é uma boa escolha. Nesse caso, quase todos os sistemas Unix possuem 2 bons utilitários:

basename
dirname

O primeiro extrairá o nome do arquivo, enquanto o segundo extrairá o caminho; portanto, se você tiver $ 0, diga:

dirname $0

E você vai pegar o caminho.

Felicidades

D4RIO
fonte
nomedir pode retornar caminhos relativos
opticyclic
0

Apresentando o pwd, o bash embutido. Também encontrado no pacote GNU coreutils.

$ sh ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
$0: ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
cheeky binary from /home/jaroslav/tmp (/home/jaroslav/tmp)

$ cat /home/jaroslav/tmp/somewhere.sh

abs=$( cd `dirname "$0"` ; pwd -P)
absBin=$( cd `dirname "$0"` ; /bin/pwd -P)
echo \$0: $0
echo cheeky binary from $abs \($absBin\)
Ярослав Рахматуллин
fonte