Estou tentando obter o caminho absoluto para o script em execução no OS X.
Eu vi muitas respostas acontecendo readlink -f $0
. No entanto, como o OS X readlink
é igual ao do BSD, ele simplesmente não funciona (funciona com a versão do GNU).
Existe uma solução out-of-the-box para isso?
$( cd "$(dirname "$0")" ; pwd -P )
Respostas:
Há uma
realpath()
função C que fará o trabalho, mas não estou vendo nada disponível na linha de comando. Aqui está uma substituição rápida e suja:Isso imprime o caminho literalmente se ele começar com a
/
. Caso contrário, deve ser um caminho relativo, portanto, antecede$PWD
à frente. A#./
parte é removida./
da frente$1
.fonte
realpath ../something
retorna$PWD/../something
command -v realpath >/dev/null 2>&1 || realpath() { ... }
Essas três etapas simples vão resolver este e muitos outros problemas do OS X:
brew install coreutils
grealpath .
(3) pode ser alterado para apenas
realpath
, consulte (2) saídafonte
$( cd "$(dirname "$0")" ; pwd -P )
funcionam bem para mim.XXX
e alguémcd xxx
, em seguida,pwd
irá retornar.../xxx
. Exceto por essa resposta, todas as soluções acima retornamxxx
quando o que você realmente desejaXXX
. Obrigado!realpath
, o que acontece quando é quase certo que você vai precisar de outros itenscoreutils
? Reescrever essas funções no bash também? : PUgh. Achei as respostas anteriores um pouco inadequadas por alguns motivos: em particular, elas não resolvem vários níveis de links simbólicos e são extremamente "Bash-y". Embora a pergunta original peça explicitamente um "script Bash", ela também menciona o Mac OS X, semelhante ao BSD, não GNU
readlink
. Então aqui está uma tentativa de alguma portabilidade razoável (eu verifiquei com bash como 'sh' e traço), resolvendo um número arbitrário de links simbólicos; e também deve funcionar com espaços em branco no (s) caminho (s), embora eu não tenha certeza do comportamento se houver um espaço em branco no nome base do próprio utilitário, então talvez, hum, evitar isso?Espero que isso possa ser útil para alguém.
fonte
local
para variáveis definidas dentro da função para não poluir o namespace global. Exlocal OURPWD=...
. Funciona pelo menos para o bash.BASENAME=$(basename "$LINK")
dentro do while e usá-lo no segundo setter LINK e no setter..
pais exatamente como orealpath
faria. Com o homebrewcoreutils
instalado, tenteln -s /var/log /tmp/linkexample
entãorealpath /tmp/linkexample/../
; isso imprime/private/var
. Mas sua função produz em/tmp/linkexample/..
vez disso, porque..
não é um link simbólico.Uma variante mais amigável da linha de comando da solução Python:
fonte
python -c "import os; import sys; print(os.path.realpath(sys.argv[1]))"
Eu estava procurando uma solução para usar em um script de provisionamento de sistema, ou seja, rodar antes mesmo de o Homebrew ser instalado. Na falta de uma solução adequada, eu apenas transferia a tarefa para uma linguagem de plataforma cruzada, por exemplo, Perl:
Mais frequentemente, o que realmente queremos é o diretório que o contém:
fonte
FULLPATH=$(perl -e "use Cwd 'abs_path'; print abs_path('$0')")
. Alguma razão contra?''
não é à prova de balas. Quebra se$0
contiver aspas simples, por exemplo. Um exemplo muito simples: experimente sua versão em/tmp/'/test.sh
, e chame/tmp/'/test.sh
por seu caminho completo./tmp/'.sh
,.Uma vez que existe um caminho real como outros apontaram:
Makefile:
Em seguida, compile
make
e coloque um link simbólico com:ln -s $(pwd)/realpath /usr/local/bin/realpath
fonte
gcc realpath.c -o /usr/local/bin/realpath
?/usr/local/bin
Use Python para obtê-lo:
fonte
dirname
fornecerá o nome do diretório de/path/to/file
, ou seja/path/to
.cd /path/to; pwd
garante que o caminho seja absoluto.basename
fornecerá apenas o nome do arquivo em/path/to/file
, ou sejafile
.fonte
Como você pode ver acima, experimentei isso há cerca de 6 meses. Eu me esqueci totalmente sobre isso até que eu me descobri precisando de algo semelhante novamente. Fiquei completamente chocado ao ver o quão rudimentar era; Tenho me ensinado a programar intensamente por cerca de um ano, mas muitas vezes sinto que talvez não tenha aprendido nada quando as coisas estão no pior.
Eu removeria a 'solução' acima, mas eu realmente gosto dela ser um registro do quanto eu realmente aprendi nos últimos meses.
Mas estou divagando. Sentei-me e resolvi tudo ontem à noite. A explicação nos comentários deve ser suficiente. Se você deseja rastrear a cópia na qual estou trabalhando, pode seguir o seguinte. Isso provavelmente faz o que você precisa.
fonte
..
referências pai; por exemplo,/foo/link_to_other_directory/..
é resolvido como/foo
em vez do pai de qualquer caminho para o qual o link simbólico/foo/link_to_other_directory
aponta.readlink -f
erealpath
resolva cada componente do caminho começando na raiz e atualizando os destinos de link anteriores para o restante ainda sendo processado. Eu adicionei uma resposta a esta pergunta, reimplementando essa lógica.realpath para Mac OS X
Exemplo com caminho relacionado:
Exemplo com pasta pessoal
fonte
..
ele não produz a resposta certa, então adicionei uma verificação se o caminho fornecido é um diretório:if test -d $path ; then echo $(cd "$path"; pwd) ; else [...]
"$(dirname $(dirname $(realpath $0)))"
mas funciona, então preciso de outra coisa ...echo
também não deve ser perpetrado...
as referências dos pais antes de resolver os links simbólicos, não depois; tente fazer isso com o homebrewcoreutils
instalado, crie um link comln -s /var/log /tmp/linkexample
e executerealpath /tmp/linkexample/../
; isso imprime/private/var
. Mas sua função produz em/tmp/linkexample/..
vez disso, porquepwd
ainda aparece/tmp/linkexample
após o cd.No macOS, a única solução que encontrei para isso que lida com links simbólicos de maneira confiável é usando
realpath
. Como isso exigebrew install coreutils
, eu apenas automatizei essa etapa. Minha implementação é assim:Este erro ocorrerá se eles não tiverem
brew
instalado, mas você também pode instalar apenas isso. Eu simplesmente não me sentia confortável automatizando algo que retira código Ruby arbitrário da rede.Observe que esta é uma variação automática da resposta de Oleg Mikheev .
Um teste importante
Um bom teste de qualquer uma dessas soluções é:
ln -s
) para esse arquivoA solução remove a referência do link simbólico e fornece o diretório original? Se for assim, funciona.
fonte
Isso parece funcionar para OSX, não requer nenhum binário e foi extraído daqui
fonte
Eu gosto disso:
fonte
Eu precisava de uma
realpath
substituição no OS X, que funcionasse corretamente em caminhos com links simbólicos e referências de pais exatamente comoreadlink -f
faria . Isso inclui resolver links simbólicos no caminho antes de resolver as referências dos pais; por exemplo, se você instalou acoreutils
garrafa homebrew , execute:Observe que
readlink -f
foi resolvido/tmp/linkeddir
antes de resolver a..
referência do dir pai. Claro, não há nenhumreadlink -f
no Mac também .Portanto, como parte da implementação de um bash para,
realpath
reimplementei o que umacanonicalize_filename_mode(path, CAN_ALL_BUT_LAST)
chamada de função GNUlib faz , no Bash 3.2; esta é também a chamada de função que o GNUreadlink -f
faz:Inclui detecção de link simbólico circular, saindo se o mesmo caminho (intermediário) for visto duas vezes.
Se tudo que você precisa é
readlink -f
, então você pode usar o acima como:Pois
realpath
, eu também precisava--relative-to
e--relative-base
suporte, que fornecem caminhos relativos após a canonização:Incluí testes de unidade em minha solicitação de revisão de código para este código .
fonte
Com base na comunicação com o comentarista, concordei que é muito difícil e não há uma maneira trivial de implementar um realpath que se comporte totalmente da mesma forma que o Ubuntu.
Mas a versão a seguir, pode lidar com casos de canto, a melhor resposta não pode e satisfazer minhas necessidades diárias no macbook. Coloque este código em seu ~ / .bashrc e lembre-se:
fonte
echo
. Apenaspwd
faz o mesmo queecho $(pwd)
sem ter que gerar uma segunda cópia do shell. Além disso, não citar o argumento deecho
é um bug (você perderá qualquer espaço em branco à esquerda ou à direita, qualquer caractere de espaço em branco interno adjacente e terá os curingas expandidos, etc). Veja mais stackoverflow.com/questions/10067266/…realpath
arquivo de um diretório inexistente.dir=$(dirname "$1"); file=$(basename "$1")
vez da sintaxe de crase obsoleta. Observe também a citação correta de argumentos, novamente.