Ou seja, temporariamente (em um sub-shell) cdpara o diretório que contém o arquivo e, em seguida, construa o nome do caminho absoluto usando o valor $PWDe o componente nome do arquivo do nome do caminho. O -Pé necessário para evitar cdo tratamento especial dos ..componentes. Ele tem o efeito colateral de resolver componentes de links simbólicos no próprio diretório. No entanto, se o arquivo em si for um link simbólico, ele não será resolvido (essa é uma diferença do zshmodificador :Pde ).
Definimos OLDPWDpara -contornar o fato de que cd -P -- -faz um chdir($OLDPWD)em vez de chdir("-")(esse truque funciona, bashmas não em todas as outras shimplementações).
Dependendo do sistema operacional, usar a função sem argumento retornará o caminho absoluto do diretório atual ou apresentará um erro. Em versões futuras do bash, isso provavelmente será um erro em todos os sistemas, pois cd ''falhar se tornará um requisito POSIX.
Bash vem com uma realpathextensão carregável. Como o bash-4.4 deve ser instalado por padrão¹, você deve poder fazer:
BASH_LOADABLES_PATH=${BASH_LOADABLES_PATH:-/usr/local/lib/bash:/usr/lib/bash}
enable -f realpath realpath
realpath ..
help realpath
Uma vez habilitado, cada comando carregável se torna um "real" embutido sem sobrecarga adicional de fork/exec e com a capacidade de manipular o ambiente bash (quando oferecido, por exemplo, o mypidcarregável).
A -fopção especifica o caminho para o binário de extensão carregável, se não estiver no local esperado ou sua distro não o configurou corretamente, você precisará definir a variável BASH_LOADABLES_PATHpara o diretório que contém as extensões (ou, use -fcom o caminho completo para o carregável). Se estiver definido corretamente, você não precisará da primeira linha acima.
Ao escrever scripts portáteis que preferem, mas não exigem tais extensões, usarei uma função wrapper de qualquer maneira — nos moldes de @Kusalananda — para que possa retornar a um externo (como readlinkou realpathde coreutils ).
Esta extensão está disponível desde o bash-2.05, mas antes do bash-4.4 as extensões não eram compiladas e instaladas por padrão, embora seja simples fazê-lo se você tiver um ambiente de compilação funcional (compilador C etc.). As distribuições podem ou não incluir as extensões, infelizmente o RHEL 8 (e, portanto, o CentOS 8) constrói o bash-4.4 com as extensões carregáveis deliberadamente removidas.
Sugiro o seguinte, que tem uma alta probabilidade de funcionar em sistemas operacionais não Linux (incluindo AIX). Para calcular um caminho absoluto (ou seja, um caminho começando em /):
Ao testar outras soluções possíveis (incluindo uma chamada para realpath), você notará uma diferença significativa dependendo se o componente do último caminho existe ou não e se o componente do último caminho é ou não um link simbólico.
Alguns sistemas possuem o comando "realpath", por exemplo, Ubuntu. Você pode tentar realpath ~/foo.txte pode dar algo como /home/user/foo.txt, então você pode usar basedirpara cortar o nome do arquivo.
O
bash
shell não possui uma maneira interna de obter explicitamente um caminho absoluto dado um nome de caminho relativo.Na
zsh
casca, pode-se fazere
/home/kk/.zshenv
voltar (observe que ele também resolve todos os links simbólicos sempre que possível de maneira semelhanterealpath()
).Em
bash
, você poderia, para um nome de caminho designando um não-diretório e supondo que você tenha acesso de pesquisa ao seu diretório pai, useOu seja, temporariamente (em um sub-shell)
cd
para o diretório que contém o arquivo e, em seguida, construa o nome do caminho absoluto usando o valor$PWD
e o componente nome do arquivo do nome do caminho. O-P
é necessário para evitarcd
o tratamento especial dos..
componentes. Ele tem o efeito colateral de resolver componentes de links simbólicos no próprio diretório. No entanto, se o arquivo em si for um link simbólico, ele não será resolvido (essa é uma diferença dozsh
modificador:P
de ).Definimos
OLDPWD
para-
contornar o fato de quecd -P -- -
faz umchdir($OLDPWD)
em vez dechdir("-")
(esse truque funciona,bash
mas não em todas as outrassh
implementações).Para um caminho de diretório é mais fácil:
Isso obviamente poderia ser colocado em uma função shell por conveniência:
(Observe que toda essa função é definida em um subshell para evitar a alteração do diretório de trabalho do shell de chamada.)
Testando esta função:
Dependendo do sistema operacional, usar a função sem argumento retornará o caminho absoluto do diretório atual ou apresentará um erro. Em versões futuras do
bash
, isso provavelmente será um erro em todos os sistemas, poiscd ''
falhar se tornará um requisito POSIX.Bash vem com uma
realpath
extensão carregável. Como o bash-4.4 deve ser instalado por padrão¹, você deve poder fazer:Uma vez habilitado, cada comando carregável se torna um "real" embutido sem sobrecarga adicional de fork/exec e com a capacidade de manipular o ambiente bash (quando oferecido, por exemplo, o
mypid
carregável).A
-f
opção especifica o caminho para o binário de extensão carregável, se não estiver no local esperado ou sua distro não o configurou corretamente, você precisará definir a variávelBASH_LOADABLES_PATH
para o diretório que contém as extensões (ou, use-f
com o caminho completo para o carregável). Se estiver definido corretamente, você não precisará da primeira linha acima.Ao escrever scripts portáteis que preferem, mas não exigem tais extensões, usarei uma função wrapper de qualquer maneira — nos moldes de @Kusalananda — para que possa retornar a um externo (como
readlink
ourealpath
de coreutils ).Sugiro o seguinte, que tem uma alta probabilidade de funcionar em sistemas operacionais não Linux (incluindo AIX). Para calcular um caminho absoluto (ou seja, um caminho começando em
/
):Para um caminho canônico (ou seja, um com todos os links simbólicos expandidos):
Ao testar outras soluções possíveis (incluindo uma chamada para
realpath
), você notará uma diferença significativa dependendo se o componente do último caminho existe ou não e se o componente do último caminho é ou não um link simbólico.Alguns sistemas possuem o comando "realpath", por exemplo, Ubuntu. Você pode tentar
realpath ~/foo.txt
e pode dar algo como/home/user/foo.txt
, então você pode usarbasedir
para cortar o nome do arquivo.