Alguns dos meus colegas de trabalho preferem escrever o seguinte no topo de seus scripts BASH para determinar o diretório que contém o script:
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
Enquanto eu prefiro o seguinte:
SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
(Observe que, na maioria dos casos, não nos importamos em resolver links simbólicos, por isso tendemos a usar estes em vez de eg readlink
)
Há algum mérito da cd ... && pwd
abordagem em relação à dirname
abordagem -only? Parece que ela está apenas realizando etapas extras para atingir exatamente o mesmo resultado, mas quero ter certeza de que não há nenhuma nuance que eu esteja perdendo.
O ponto de:
O que deveria ser:
É que ele fornece um caminho absoluto (e com
-P
, o caminho absoluto canônico , orealpath()
), enquanto$BASH_SOURCE
($var
é a abreviação de${var[0]}
no bash, como no ksh) pode muito bem ser um caminho relativo, como../file.bash
.Sem
-P
, no caso de../file.bash
,cd ..
pode muito bem levá-lo a um diretório diferente daquele que o script define como padrão (novamente como no ksh que introduziu o recurso (incorreto)cd
faz uma travessia lógica ondecd ..
não,chdir("..")
mas simchdir(dirname($PWD))
(e$PWD
terá componentes de link simbólico se você tivercd
inserido caminhos com componentes de link simbólico anteriormente).Definimos
CDPATH
para a string vazia (o que, até ondecd
se sabe, é equivalente a desconfigurar), caso esteja definido para outra coisa porque, por exemplo, há uma variável com esse nome no ambiente, pois, do contrário, umcd
com um caminho relativo (como noBASH_SOURCE=dir/file.bash
caso) poderia levá-lo para outro lugar. Pode ser uma boa ideia desconfigurarCDPATH
globalmente, mas se esse script for destinado a ser originado, pode não ser aceitável.Observe que isso ainda não funciona corretamente se o nome do diretório
BASH_SOURCE
ou seu caminho real terminarem em caracteres de nova linha (já que a substituição de comando remove todos os caracteres de nova linha finais, não apenas aquele adicionado pordirname
/pwd
para saída) ou se$BASH_SOURCE
for ,-/file
por exemplo (comocd -
é a abreviação decd -- "$OLDPWD"
).Abordar o último e, de forma mais geral, ter uma
cd
abordagem mais próxima do quechdir()
é encontrado em linguagens de programação não shell poderia ser feito com uma função auxiliar usando a recomendação POSIX :Onde prefixar caminhos relativos com
./
evita a necessidade de--
e aborda o-
problema como./-
contrário a-
não é interpretado como o diretório anterior . Veja lá por que a string vazia é tratada especialmente. Esse./
prefixo também desabilitaCDPATH
o tratamento, então oCDPATH=
acima não é necessário, exceto como um lembrete de que essechdir
auxiliar desabilitaCDPATH
o tratamento.No zsh, você faria apenas:
Ou:
Onde
:P
você obtém orealpath()
e:h
o cabeçalho (dirname, como em csh).Ambos não necessariamente darão o mesmo resultado se
$0
forem um link simbólico.Eles não apresentam nenhum dos problemas da abordagem bash acima.
Francamente, eu diria que ambos são desnecessariamente complicados (e eu estaria errado; veja a resposta de Stéphane que explica que é assim que se faz se você precisa resolver para caminhos absolutos). Mesmo sua versão mais simples ainda está chamando um comando externo onde nenhum é necessário. Por que não fazer apenas:
Quanto a esses dois, não vejo nenhum benefício na abordagem ainda mais complicada usando dois comandos externos. Por que executar
pwd
se você pode usar$PWD
, mas por que executar tantos comandos em primeiro lugar? Se você precisasse resolver links simbólicos, então eu poderia entender trazer comandos externos, mas para algo tão simples quanto isso?Agora, há casos extremos em que isso falha. Conforme explicado por Stéphane Chazelas em um comentário (agora deletado):
Se isso é relevante ou não no seu caso é algo que só você pode saber.
A propósito, você realmente não quer usar CAPS para nomes de variáveis de shell. Como, por convenção , variáveis de ambiente globais são capitalizadas, é uma má prática usar também caps para suas próprias variáveis locais, porque isso pode levar a colisões de nomes e bugs difíceis de encontrar.