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.

Tim
fonte
Uma questão relacionada recentemente veio aqui: Obter caminho do script atual quando executado através de uma ligação simbólica
Caleb
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.

rozcietrzewiacz
fonte
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)"
Caleb
fonte
@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"
Michael Mrozek
fonte
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

David Kennedy
fonte
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.

Brettski
fonte
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).

Stéphane Chazelas
fonte
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
Michael Dillon
fonte