Consulte um arquivo no mesmo diretório de um script encontrado em $ PATH


33

Eu tenho um arquivo de script bash, que é colocado em algum diretório adicionado ao $ PATH para que eu possa chamar o script de qualquer diretório.

Há outro arquivo de texto no mesmo diretório que o script. Gostaria de saber como se referir ao arquivo de texto no script?

Por exemplo, se o script for apenas para gerar o conteúdo do arquivo de texto, cat textfilenão funcionará, pois ao chamar o script de um diretório diferente, o arquivo de texto não será encontrado.



Esta pergunta respostas como obter uma festança caminho arquivos de script de forma confiável, eu acrescentou que para o meu caminho: stackoverflow.com/q/4774054/1695680
ThorSummoner

Respostas:


24

Eles devem funcionar da mesma forma, desde que não haja links simbólicos (na expansão do caminho ou no próprio script):

  • MYDIR="$(dirname "$(realpath "$0")")"

  • MYDIR="$(dirname "$(which "$0")")"

  • Uma versão em duas etapas de qualquer uma das opções acima:

    MYSELF="$(realpath "$0")"

    MYDIR="${MYSELF%/*}"

Se houver um link simbólico no caminho para o seu script, whichvocê fornecerá uma resposta que não incluirá a resolução desse link. Se realpathnão estiver instalado por padrão no seu sistema, você pode encontrá-lo aqui .

[EDIT]: Como parece que realpathnão tem vantagem sobre o readlink -f sugerido por Caleb , provavelmente é melhor usar o último. Meus testes de tempo indicam que é realmente mais rápido.


Sem problemas. A propósito, de onde realpathvem no seu sistema. (Para outros que não tem isso, você pode usarreadlink -f
Caleb

@ Caleb Na verdade, eu pensei que pertencia ao conjunto de utilitários GNU padrão (coreutils), mas agora vejo que é um pacote separado .
rozcietrzewiacz

O @rozcietrzewiacz realpathdata de antes readlink -f(e até mesmo do readlinkIIRC) estava no coreutils do GNU (havia várias ferramentas semelhantes por aí. readlink -feventualmente se tornou o padrão de fato); realpathé mantido apenas para compatibilidade com scripts que ainda o utilizam.
Gilles 'SO- stop be evil' em

Qual é a vantagem de $(dirname "$(which "$0")")mais de $(dirname $0)onde o whichnão está mais presente? Não é o mesmo?
UlfR

readlink -fparece não funcionar no Mac OS X 10.11.6, mas realpathfunciona imediatamente .
Grav

9

Meus sistemas não têm realpath como sugerido por rozcietrzewiacz .

Você pode fazer isso usando o readlinkcomando A vantagem de usar isso sobre a análisewhich ou outras soluções é que, mesmo que uma parte do caminho ou o nome do arquivo executado fosse um link simbólico, você seria capaz de encontrar o diretório onde estava o arquivo real.

MYDIR="$(dirname "$(readlink -f "$0")")"

Seu arquivo de texto pode ser lido em uma variável como esta:

TEXTFILE="$(<$MYDIR/textfile)"

@rozcietrzewiacz: Na verdade, eu não estava me referindo apenas à sua whichsugestão. A solução normal para isso envolve apenas dirnameou uma combinação de cde pwdem um subshell. O Readlink tem a vantagem aqui. realpathparece ser apenas um invólucro de readlink -fqualquer maneira.
Caleb

Não sei como realpathé diferente readlink -f. Só posso ver que me dá os mesmos resultados (em oposição a which).
rozcietrzewiacz

Lembre-se de que readlink -f(do GNU coreutils) NÃO requer que o último elemento do caminho exista, requer readlink -e, mas não é suportado por busybox readlink, o que imita o comportamento de -esuas -fopções.
dragon788

8

$0no script, será o caminho completo para o script e dirnameseguirá um caminho completo e fornecerá apenas o diretório, para que você possa fazer isso no arquivo de texto cat:

$ cat "$(dirname -- "$0")/textfile"

Enquanto isso parece funcionar sem realpath $0, você está errado ao dizer que " $0no script será o caminho completo para o script".
rozcietrzewiacz 31/07

@roz De que maneira?
Michael Mrozek

1
$0é o comando como foi executado, o que pode ser por exemplo ../script.sh.
rozcietrzewiacz 31/07

Portanto, na verdade, $(dirname "$0")retorna o caminho relativo para o script, como parte do comando chamado - não o caminho absoluto. Isso pode causar problemas nos scripts que alteram os diretórios durante a execução.
rozcietrzewiacz 31/07

@roz Ah, interessante. Então, acho que não causaria um problema aqui, já que ele está chamando algo no caminho pelo nome, mas isso quebraria outras coisas. Obrigado
Michael Mrozek

4

Você pode colocar isso na parte superior do seu script:

cd "${BASH_SOURCE%/*}" || exit

A variável bash interna BASH_SOURCE é na verdade uma matriz de nomes de caminho. Se você expandi-lo como uma string simples, por exemplo, "$ BASH_SOURCE", obterá o primeiro elemento, que é o nome do caminho da função ou script em execução no momento.

Fonte: http://mywiki.wooledge.org/BashFAQ/028


2

Eu estava tentando isso e o caminho real não funcionou para mim. A solução que eu usei é:

SCRIPTDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )

O que funcionou bem até agora. Gostaria de saber se existem problemas em potencial com a abordagem.


1
Bom, mas não segue links simbólicos. Tente isto:SCRIPT_DIR="$( cd "$(dirname "$( readlink -f ${BASH_SOURCE[0]} )")" >/dev/null 2>&1 && pwd)"
OronNavon 25/08

1

Eu uso:

#! /bin/sh -
dir=$(cd -P -- "$(dirname -- "$0")" && pwd -P) || exit
dosomethingwith "${dir%/}/some-file"

Que é POSIX e deve funcionar, desde que o nome do diretório $0não termine com caracteres de nova linha, não esteja -e $CDPATHnão esteja definido (e possivelmente alguns outros casos de canto se o script não foi pesquisado $PATH).


0

Eu sempre uso whichpara encontrar o caminho completo de um executável do PATH. Por exemplo:

which python

Se você combinar isso com o dirnamecomando, obterá:

wp=`which python`
dn=`dirname $wp`
ls $dn
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.