O que é uma maneira portátil de um script (zsh) determinar seu caminho absoluto?
No Linux eu uso algo como
mypath=$(readlink -f $0)
... mas isso não é portátil. (Por exemplo, readlink
no darwin não reconhece a -f
bandeira, nem tem equivalente.) (Além disso, usar readlink
para isso é, na verdade, um truque bastante obscuro.)
O que é uma maneira mais portátil?
Respostas:
Com
zsh
, é apenas:Agora para outras conchas, embora
realpath()
ereadlink()
são funções padrão (o último sendo uma chamada de sistema),realpath
ereadlink
não são de comando padrão, embora alguns sistemas têm um ou outro ou ambos com vários comportamentos e conjunto de recursos.Com frequência, para portabilidade, você pode recorrer a
perl
:Isso se comportaria mais como o GNU do
readlink -f
querealpath()
(GNUreadlink -e
), pois ele não reclamará se o arquivo não existir enquanto o nome do diretório existir.fonte
.zshrc
: consulte esta postagem .No zsh, você pode fazer o seguinte:
Ou, para obter o diretório em que o script reside:
Fonte: página de manual zshexpn (1), seção EXPANSÃO DE HISTÓRIA, Modificadores de subseção (ou simplesmente
info -f zsh -n Modifiers
).fonte
readlink -f
preferiria ser$0:A
.Estou usando isso há vários anos:
fonte
readlink -f
é quando o próprio script é um link simbólico.zsh
, se eu executar isso diretamente ou no subshell (como sugerido) enquanto estiver no meu diretório home (/home/ville
), ele será impresso/home/ville/zsh
.Esta sintaxe deve ser portável para qualquer intérprete estilo shell Bourne (testado com
bash
,ksh88
,ksh93
,zsh
,mksh
,dash
ebusybox sh
):Esta versão adiciona compatibilidade ao shell AT&T Bourne herdado (não POSIX):
fonte
$PWD
pode ser um exagero - você pode configurá-la como uma corrente absolutacd -P .
. Duvido que funcione em bourneshell - mas deve funcionar em todos os que você testou pela primeira vez. faz por mim de qualquer maneira.zsh
edirname
mas rapidamente retirar hir / seu comentário ...Supondo que você realmente quis dizer o caminho absoluto, ou seja, um caminho do diretório raiz:
A propósito, isso funciona em qualquer shell no estilo Bourne.
Se você quis dizer um caminho com todos os links simbólicos resolvidos, isso é outra questão.
readlink -f
funciona no Linux (excluindo alguns sistemas BusyBox simplificados), FreeBSD, NetBSD, OpenBSD e Cygwin, mas não no OS / X, AIX, HP / UX ou Solaris. Se você tiverreadlink
, você pode chamá-lo em um loop:Se você não possui
readlink
, é possível aproximarls -n
, mas isso só funciona sels
não alterar nenhum caractere não imprimível no nome do arquivo.(O extra
z
é no caso de o destino do link terminar em uma nova linha, cuja substituição de comando consumiria de outra forma. Arealpath
função não trata desse caso para nomes de diretório, a propósito.)fonte
ls
implementação que manipule caracteres não imprimíveis quando a saída não for para um terminal.touch Stéphane; LC_ALL=C busybox ls Stéphane | cat
→St??phane
(ou seja, se o nome estiver em UTF-8, latin1 oferece um único?
). Acho que já vi isso também em escritórios comerciais mais antigos.busybox
é isso? de acordo com o gitbusybox ls
não mudou de código desde 2011. Meubusybox ls
- por volta de 2013 - não faz isso. Este um - circa 2012 - faz . Isso pode explicar o porquê. Você construiu seubusybox
com suporte a Unicode - para incluir suporte a wchar? Você pode tentar, ou mais, para verificar as opções de compilação nomkinitcpio
busybox
pacote.Desde que você tenha permissões de execução no diretório atual - ou no diretório a partir do qual você executou o shell script - se desejar um caminho absoluto para um diretório, tudo o que você precisa é
cd
.Etapa 10 das
cd
especificações deE em
pwd -P
É porque
cd -P
é necessário definir o diretório de trabalho atual como o quepwd -P
deve ser impresso e quecd -
deve ser impresso$OLDPWD
conforme o seguinte:SAÍDA
espere por isso...
SAÍDA
E quando eu imprimo com
cd -
estou imprimindo$OLDPWD
.cd
define$PWD
assim quecd -P .
$PWD
agora for um caminho absoluto para/
- então não preciso de outras variáveis. E, na verdade, eu nem deveria precisar da trilha,.
mas há um comportamento especificado de redefinir$PWD
para$HOME
em um shell interativo quando nãocd
é adornado. Portanto, é apenas um bom hábito para se desenvolver.Portanto, basta fazer o acima no caminho
${0%/*}
deve ser mais do que suficiente para verificar$0
o caminho, mas, no caso em$0
si, é um link direto, você provavelmente não poderá alterar o diretório nele, infelizmente.Aqui está uma função que irá lidar com isso:
Ele se esforça para fazer o máximo que pode no shell atual - sem chamar um subshell - embora existam subshells invocados para erros e links flexíveis que não apontam para diretórios. Depende de um shell compatível com POSIX e de um espaço para nome
ls
limpo, compatível com POSIX_function()
. Ele ainda funcionará bem sem o último, embora possa sobrescreverunset
algumas funções atuais do shell nesse caso. Em geral, todas essas dependências devem estar disponíveis de maneira confiável em uma máquina Unix.Chamada com ou sem argumentos, a primeira coisa que faz é redefinir
$PWD
para seu valor canônico - resolve todos os links para seus alvos, conforme necessário. Chamado sem argumentos e é isso; mas ligou para eles e resolverá e canonizará o caminho para cada um ou então imprimirá uma mensagem dizendostderr
por que não.Como ele opera principalmente no shell atual, deve ser capaz de lidar com uma lista de argumentos de qualquer tamanho. Ele também procura a
$_zdlm
variável (que tambémunset
é quando\n
termina ) e imprime seu valor escapado de C imediatamente à direita de cada um de seus argumentos, sendo que cada um deles é sempre seguido também por um único caractere de linha de linha.Ele altera bastante o diretório, mas, além de defini-lo com seu valor canônico, ele não afeta
$PWD
, embora$OLDPWD
não possa, de forma alguma, ser contado quando terminar.Ele tenta encerrar cada um de seus argumentos o quanto antes. Ele primeiro tenta
cd
entrar$1
. Se puder, imprime o caminho canônico do argumento parastdout
. Se não puder, verifica se$1
existe e não é um link flexível. Se verdadeiro, ele imprime.Dessa maneira, ele lida com qualquer argumento de tipo de arquivo que o shell tenha permissões para endereçar, a menos que
$1
seja um link simbólico que não aponte para um diretório. Nesse caso, ele chamawhile
loop em um subshell.Chama
ls
para ler o link. O diretório atual deve ser alterado para seu valor inicial primeiro, a fim de manipular com segurança quaisquer caminhos de referência e, portanto, no subshell de substituição de comando, a função:Ele tira da esquerda da
ls
saída o mínimo necessário para conter completamente o nome do link e a string->
. Embora eu tenha tentado evitar issoshift
e, ao que$IFS
parece, esse é o método mais confiável o mais próximo possível. É a mesma coisa que o poor_mans_readlink de Gilles faz - e é bem feito.Ele repetirá esse processo em um loop até que o nome do arquivo retornado
ls
definitivamente não seja um link vinculado. Nesse ponto, canoniza esse caminho como antes ecd
depois imprime.Exemplo de uso:
SAÍDA
Ou possivelmente ...
SAÍDA
fonte
que tal um liner simpático quando existe python disponível para impedir a redefinição de um algoritmo?
mesmo que https://stackoverflow.com/a/7305217
fonte