Como recuperar o caminho absoluto de um arquivo arbitrário do OS X

18

Estou procurando um comando simples que possa ser usado no Bash para encontrar o caminho absoluto e canonizado para um arquivo em um OS X (semelhante a '' readlink -f '' no Linux).

A seguinte sessão de bash de amostra descreve um utilitário [fictício] chamado '' abspath '' que exibe o comportamento desejado:

$ pwd
/Users/guyfleegman

$ ls -lR
drwxr-xr-x  4 guyfleegman  crew  136 Oct 30 02:09 foo

./foo:
-rw-r--r--  1 guyfleegman  crew  0 Oct 30 02:07 bar.txt
lrwxr-xr-x  1 guyfleegman  crew  7 Oct 30 02:09 baz.txt -> bar.txt


$ abspath .
/Users/guyfleegman

$ abspath foo
/Users/guyfleegman/foo

$ abspath ./foo/bar.txt
/Users/guyfleegman/foo/bar.txt

$ abspath foo/baz.txt
/Users/guyfleegman/foo/baz.txt

Como na última chamada de '' abspath '' no exemplo acima, eu preferiria que não resolvesse automaticamente links simbólicos, mas não vou ser muito exigente aqui.

    
por Michael Wehner 30.10.2010 / 11:53

9 respostas

16

function abspath() { pushd . > /dev/null; if [ -d "$1" ]; then cd "$1"; dirs -l +0; else cd "'dirname \"$1\"'"; cur_dir='dirs -l +0'; if [ "$cur_dir" == "/" ]; then echo "$cur_dir'basename \"$1\"'"; else echo "$cur_dir/'basename \"$1\"'"; fi; fi; popd > /dev/null; }

Exemplos:

abspath / => /

abspath /.DS_Store => /.DS_Store

abspath ~ => /Users/mschrag

cd /tmp; abspath . => /tmp

cd /; abspath .DS_Store => /.DS_Store
    
por 05.12.2010 / 17:01
11

Eu não acho que haja um comando buildin que faça isso. Jesse Wilson escreveu um script bash para isso:

#!/bin/bash
cd -P -- "$(dirname -- "$1")" &&
printf '%s\n' "$(pwd -P)/$(basename -- "$1")"

No entanto, não funciona bem para caminhos diretamente abaixo de / , como /etc (impressão //etc ), bem como . e .. (impressão /cwd/. em ambos os casos). Eu tentei modificá-lo, mas meu bash-fu insuficiente me falhou.

Esta é minha sugestão:

#!/usr/bin/env python
import os.path
import sys

for arg in sys.argv[1:]:
    print os.path.abspath(arg)

Salvar como /usr/bin/abspath ou algo parecido e torná-lo executável. Exemplo de saída:

Servus08:~ danielbeck$ abspath .
/Users/danielbeck
Servus08:~ danielbeck$ abspath /tmp
/tmp
Servus08:~ danielbeck$ abspath Documents
/Users/danielbeck/Documents
Servus08:~ danielbeck$ abspath . /tmp Documents
/Users/danielbeck
/tmp
/Users/danielbeck/Documents

Se você fizer quiser uma resolução de link simbólico, altere a linha print desta forma:

    print os.path.realpath(os.path.abspath(arg))

para obter isso:

Servus08:~ danielbeck$ abspath . /tmp Documents
/Users/danielbeck
/private/tmp
/Users/danielbeck/Documents
    
por 30.10.2010 / 12:49
8

Uma opção seria apenas instalar o coreutils e usar greadlink -f . Ele resolve links simbólicos e funciona com /Foo/ ou ~/foo.txt se eles não existirem, mas não com /Foo/foo.txt se /Foo/ não existir.

$ brew install coreutils
$ greadlink -f /etc
/private/etc
$ greadlink -f ~/Documents/
/Users/lauri/Documents
$ greadlink -f ..
/Users
$ greadlink -f //etc/..////
/private
$ greadlink -f /Foo
/Foo
$ greadlink -f /Foo/foo.txt
$ 

Isso não resolve links simbólicos e também não funciona com /Foo/foo.txt .

abspath() {
  if [ -d "$1" ]; then
    ( cd "$1"; dirs -l +0 )
  else
    ( cd "$(dirname "$1")"; d=$(dirs -l +0); echo "${d%/}/${1##*/}" )
  fi
}

abspath /etc # /etc
abspath ~/Foo/foo.txt # doesn't work
abspath ~/Foo # works
abspath .
abspath ./
abspath ../
abspath ..
abspath /
abspath ~
abspath ~/
abspath ~/Documents
abspath /\"\ \'
abspath /etc/../etc/
abspath /private//etc/
abspath /private//
abspath //private # //private
abspath ./aa.txt
abspath aa.tar.gz
abspath .aa.txt
abspath /.DS_Store
abspath ~/Documents/Books/

dirs -l realiza a expansão do til. dirs +0 imprime somente o diretório superior se houver outros diretórios na pilha.

    
por 21.08.2012 / 22:54
2

Acho que você poderia fazer isso com python ou ruby.

$ ruby -e 'puts File.expand_path("~/somepath")'

ou faça um comando com

#!/usr/bin/env ruby
puts File.expand_path(ARGV[0])
    
por 01.11.2010 / 01:50
1

Se você tiver o módulo File :: Spec instalado para o perl, basta fazer isso:

perl -MFile::Spec -e 'print File::Spec->rel2abs("../however/complex/../you/want/to.get"), "\n"'
    
por 10.08.2014 / 09:18
0

Se a instalação do coreutils não for uma opção, o seguinte trata de combinações de links simbólicos. e .. e funciona em arquivos e pastas como o GNU realpath faz:

#!/usr/bin/env bash
realpath()
{
    if ! pushd $1 &> /dev/null; then 
        pushd ${1##*/} &> /dev/null
        echo $( pwd -P )/${1%/*}
    else
        pwd -P
    fi
    popd > /dev/null
}

Mas não suporta o --relative-to do realpath. Isso exigiria o link .

    
por 28.11.2018 / 22:28
0

Dado que a restrição é MacOS (OS X na época), o PHP está disponível por padrão. Isso retornará o diretório raiz do arquivo. Remova dirname para obter o arquivo também.

export SOURCE_DIRECTORY="$(php -r 'echo dirname(realpath($argv[1]));' -- "${BASH_SOURCE[0]}")"
    
por 10.01.2019 / 17:41
0

Para scripts bash / sh, você pode usar essa função recursiva:

canonical_readlink ()
{
    cd 'dirname $1';
    __filename='basename $1';
    if [ -h "$__filename" ]; then
        canonical_readlink 'readlink $__filename';
    else
        echo "'pwd -P'";
    fi
}

answer=$(canonical_readlink $0)
    
por 21.08.2012 / 19:52
0

Instale a seguinte biblioteca para o OSX:

brew install coreutils

greadlink -f file.txt
    
por 05.04.2015 / 06:53