Obter o caminho do script atual quando executado por meio de um link simbólico

59

Eu tenho um utilitário que consiste em alguns diretórios com alguns scripts bash e arquivos de suporte que serão implantados em várias máquinas, possivelmente em um diretório diferente em cada máquina. Os scripts precisam ser capazes de fazer referência a caminhos relativos a si mesmos, portanto, preciso obter o caminho para o arquivo que está sendo executado no momento.

Estou ciente do dirname $0idioma que funciona perfeitamente quando meu script é chamado diretamente. Infelizmente, existe um desejo de poder criar links simbólicos para esses scripts a partir de um diretório totalmente diferente e ainda assim ter o trabalho relativo da lógica de caminhos.

Um exemplo da estrutura geral do diretório é o seguinte:

/
 |-usr/local/lib
 |  |-foo
 |  |  |-bin
 |  |  |  |-script.sh
 |  |  |-res
 |  |  |  |-resource_file.txt
 |-home/mike/bin
 |  |-link_to_script (symlink to /usr/local/lib/foo/bin/script.sh)

Como posso confiável referência /usr/local/lib/foo/res/resource_file.txtde script.shsaber se é invocado por /usr/local/lib/foo/bin/script.shou ~mike/bin/link_to_script?

Mike Deck
fonte

Respostas:

80

Tente isso como uma solução de uso geral:

DIR="$(cd "$(dirname "$0")" && pwd)"

No caso específico dos seguintes links simbólicos, você também pode fazer isso:

DIR="$(dirname "$(readlink -f "$0")")"
Caleb
fonte
Funciona perfeitamente e é muito mais simples do que as coisas que eu estava tentando. Obrigado!
Mike Deck
@MikeDeck Enjoy. Observe que eu corrigi alguns problemas de citação desde a primeira postagem ... você pode usar uma opção da edição mais recente, caso tenha espaços ou outros caracteres malucos no caminho em algum momento. Mesmo que isso não importe para este projeto, você pode copiar o código de seus próprios scripts no futuro e ter a melhor opção é importante!
Caleb
11
Devo esclarecer, o segundo funciona perfeitamente. A primeira solução que você deu não funciona para links simbólicos no meu sistema.
Mike plataforma
4
@ MikeDeck: A primeira solução funciona no caso típico de ter vários diretórios vinculados como parte do caminho, mas não ajudará se o binário final for um link simbólico. É disso que o segundo consegue cuidar.
Caleb
11
Não funciona se o arquivo de script for sourced (por exemplo $ source ./sript.sh) Isso funciona nos dois casos:DIR="$(cd "$(dirname "$BASH_SOURCE")" && pwd)"
FractalSpace 6/18
7

uma linha:

cd $(dirname $([ -L $0 ] && readlink -f $0 || echo $0))
diyism
fonte
2
As respostas de uma linha geralmente não são as mais úteis. Por favor, considere expandir sua resposta para incluir explicações, links ou documentação que suportam ainda mais a sua solução sugerida.
precisa saber é o seguinte
11
na verdade, você não precisa fazer isso, versão readlink da resposta original funciona muito bem se há ligação simbólica a todos os envolvidos
THESorcerer
3

readlink -f não funciona para mim, eu tenho esse erro:

readlink: illegal option -- f
usage: readlink [-n] [file ...]

Mas isso funciona bem:

DIR="$(dirname "$(readlink "$0")")"
echo $DIR
Kevin Campion
fonte
3
Então você está em um Mac e isso deve responder à sua pergunta .
Isaac
Sim, estou no MacOs @isaac, mas não tenho nenhuma pergunta. Postei o comando que funciona do meu lado.
Kevin Campion
0

Uma pequena adição ao script acima. A opção -P para pwd segue links simbólicos

DIR="$(cd "$(dirname "$0")" && pwd -P)"
user2108420
fonte
7
Isso funciona apenas quando o link simbólico faz parte da estrutura de diretórios. Não funciona quando o próprio arquivo está vinculado.
Oliver Gondža