Como determinar o caminho absoluto para um arquivo em um script de shell


2

Estou escrevendo um script genérico que pode ser passado nos caminhos absoluto e relativo (para o atual diretório de trabalho) para os arquivos existentes.

Preciso de uma maneira à prova de falhas para transformar todos esses caminhos passados ​​em caminhos absolutos, porque preciso passar os caminhos para o comando "open", que não passará o diretório atual para o aplicativo iniciado.

Uma idéia que tive foi verificar se o caminho começa com um "/" e, se não, eu acrescentaria o caminho do diretório de trabalho atual a ele.

No entanto, gostaria de saber se existe uma solução mais inteligente para isso. Além disso, como não tenho experiência com scripts de shell e ferramentas relacionadas, nem sei como testar o valor de uma variável para começar com "/". Estou procurando uma solução portátil para executar em vários Mac, portanto, instalar ferramentas ou configurações extras seria menos do que o ideal.

Alguém pode sugerir um script padrão usando apenas ferramentas de remessa que pegam uma variável (vamos chamá-la de $ path) e a transforma em um caminho absoluto, se ainda não for absoluto?


Que idioma (s) você prefere para o seu script? Talvez esse script tenha uma função para solicitar a manipulação da expansão do caminho.
bmike

Um script "sh" simples é bom, e ele deve usar apenas os recursos disponíveis em qualquer OS X recente, ou seja, instalar ferramentas extras não é uma opção. Basicamente, os scripts obtêm o arquivo ref passado como argumento ($ 1) e eu quero transformá-lo em um caminho abs que eu possa passar para o comando "open".
Thomas Tempelmann

Gosto da opinião de @Lauri Ranta ao criar sua própria solução. É bem poderoso.
bmike

Você tem certeza de que o open não mantém o diretório atual do processo de chamada - man open -, os exemplos dizem explicitamente o diretório de trabalho atual. (caso contrário, acho que a Apple precisa de um relatório de erros) #
Mark

@ Mark, é meu próprio aplicativo que é iniciado pelo cmd aberto e, em seguida, tenta abrir os arquivos passados, por isso também pode ser que eu tenha feito algo errado lá.
Thomas Tempelmann

Respostas:


2

Uma opção seria instalar coreutils e usar greadlink -f. Ele resolve links simbólicos e funciona com /Foo/ou ~/foo.txtse eles não existem, mas não com /Foo/foo.txtse /Foo/não existe.

$ 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 os links simbólicos e também não funciona /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

dirs -lrealiza expansão til. dirs +0imprime apenas o diretório superior se houver outros diretórios na pilha. Você também pode substituir os subshells por algo como old="$PWD" ... cd "$old".

O expand_path do Ruby funciona com todos os caminhos que não existem, mas não resolve os links simbólicos.

$ ruby -e 'print File.expand_path ARGV[0]' ~/aa/bb
/Users/lauri/aa/bb$ 

Eu já vi o seu post sobre a questão mais antiga à qual o bmike estava vinculado. Agora eu peguei a versão do mschrag e isso satisfaz bem as minhas necessidades.
Thomas Tempelmann

1

Não tenho certeza se essa resposta será abrangente o suficiente para suas necessidades, mas é isso que eu faria…

--DISCLAIMER: Eu não testei isso no SH / BASH / Anything, então use isso como uma estrutura, por favor. Sinta-se à vontade para editar a pergunta depois que ela estiver funcionando! -

Você pode testar se o argumento do script fornecido começa com um caractere usando algo parecido if [[ $a == "/*" ]].

Como todos os caminhos relativos levam consigo a suposição de que o caminho de trabalho é o diretório pai, se você souber que o caminho ainda não é absoluto, poderá usá-lo pwd, assumindo que o script ou processo pai não alterou o diretório de trabalho .

Se o problema da alteração do diretório de trabalho for significativo, você precisará usar uma função como find.


Algumas notas adicionais que podem levá-lo ao caminho certo para resolver seu problema: https://unix.stackexchange.com/questions/6435/how-to-check-if-pwd-is-a-subdirectory-of-a- caminho determinado

http://www.unix.com/shell-programming-scripting/36200-getting-full-path-relative-path.html

https://stackoverflow.com/questions/2172352/in-bash-how-can-i-check-if-a-string-begins-with-some-value

Espero que isso coloque você na direção certa!


Sim, obrigado pelo teste da barra principal. Isso será suficiente para eu fazer meu próprio script funcionar. Só agora percebo que estava fazendo a pergunta de uma maneira mais geral e, portanto, verei se alguém apresenta uma solução que cubra todos os casos antes que eu marque a melhor resposta.
Thomas Tempelmann

Não use aspas /*na correspondência de padrões - entre aspas, ele trata o asterisco literalmente, e não como um curinga correspondente a todos.
Gordon Davisson

1

Ok, esqueci os casos em que o caminho poderia começar com "~". No meu caso, sei que não vou me deparar com esse caso, mas, para obter uma resposta geral útil, continuarei esperando por alguém que tenha uma solução geral. Supostamente, o comando "realpath" pode fazer isso, que está disponível no Linux, ao que parece, mas não no OSX.
Thomas Tempelmann

O realpath e o readlink não lidam com a expansão do caminho no OS X. A menos que você encontre um pacote no homebrew ou algum outro pacote de código aberto para compilar e chamar, convém lidar com isso no seu shell script ou processar no Linux.
bmike
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.