Fare riferimento a un file nella stessa directory di uno script trovato in $ PATH


33

Ho un file di script bash, che viene inserito in una directory aggiunta a $ PATH in modo da poter chiamare lo script da qualsiasi directory.

C'è un altro file di testo nella stessa directory dello script. Mi chiedo come fare riferimento al file di testo nello script?

Ad esempio, se lo script serve solo a generare il contenuto del file di testo, cat textfilenon funzionerà, poiché quando si chiama lo script da una directory diversa, il file di testo non viene trovato.



Questa domanda risponde come ottenere un file di script bash percorso in modo affidabile, ho aggiunto che sul mio cammino: stackoverflow.com/q/4774054/1695680
ThorSummoner

Risposte:


24

Dovrebbero funzionare allo stesso modo, purché non vi siano collegamenti simbolici (nell'espansione del percorso o nello script stesso):

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

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

  • Una versione in due passaggi di uno dei precedenti:

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

    MYDIR="${MYSELF%/*}"

Se è presente un whichcollegamento simbolico sulla strada per lo script, fornirà una risposta che non includa la risoluzione di tale collegamento. Se realpathnon è installato di default sul tuo sistema, puoi trovarlo qui .

[EDIT]: Siccome sembra che realpathnon abbia alcun vantaggio rispetto a quello readlink -f suggerito da Caleb , è probabilmente meglio usare quest'ultimo. I miei test di temporizzazione indicano che in realtà è più veloce.


Nessun problema. A proposito, da dove realpathviene sul tuo sistema. (Per gli altri che non ce l'hanno puoi usarereadlink -f
Caleb

@Caleb In realtà ho pensato che appartenesse al set di utility GNU standard (coreutils), ma ora posso vedere che è un pacchetto separato .
rozcietrzewiacz,

@rozcietrzewiacz realpathrisale a prima readlink -f(e persino readlink, IIRC) era in GNU coreutils (c'erano diversi strumenti simili in giro. readlink -falla fine divenne lo standard di fatto); realpathviene mantenuto solo per compatibilità con gli script che lo utilizzano ancora.
Gilles 'SO- smetti di essere malvagio'

Che cosa è il vantaggio di $(dirname "$(which "$0")")sopra $(dirname $0)dove il whichnon è più presente? Non è lo stesso?
UlfR,

readlink -fnon sembra funzionare su Mac OS X 10.11.6, ma realpathfunziona immediatamente .
Grav

9

I miei sistemi non hanno realpathcome suggerito da rozcietrzewiacz .

Puoi farlo usando il readlinkcomando. Il vantaggio di utilizzare questa soluzione rispetto all'analisi whicho ad altre soluzioni è che anche se una parte del percorso o del nome file eseguito fosse un collegamento simbolico, si sarebbe in grado di trovare la directory in cui si trovava il file effettivo.

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

Il tuo file di testo potrebbe quindi essere letto in una variabile come questa:

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

@rozcietrzewiacz: In realtà non mi riferivo solo al tuo whichsuggerimento. La soluzione normale per questo comporta sia la giusta dirnameo una combinazione di cde pwdin una subshell. Readlink ha il vantaggio qui. realpathsembra essere praticamente solo un involucro per readlink -fcomunque.
Caleb,

Non so come realpathsia diverso da readlink -f. Vedo solo che mi dà gli stessi risultati (al contrario di which).
rozcietrzewiacz,

Tieni presente che readlink -f(da GNU coreutils) NON richiede l'esistenza dell'ultimo elemento del percorso readlink -e, ma non è supportato da busybox readlink, il che imita il comportamento di -enella loro -fopzione.
dragon788,

8

$0nello script sarà il percorso completo dello script e dirnameprenderà un percorso completo e ti darà solo la directory, quindi puoi farlo per cat file di testo:

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

Mentre questo sembra funzionare senza realpath $0, sbagli nel dire che " $0nella sceneggiatura sarà il percorso completo della sceneggiatura".
rozcietrzewiacz,

@roz In che modo?
Michael Mrozek

1
$0è il comando così come è stato eseguito, che può essere ad es ../script.sh.
rozcietrzewiacz,

Quindi, in realtà $(dirname "$0")restituisce il percorso relativo allo script, come parte del comando invocato, non il percorso assoluto. Ciò può causare problemi negli script che cambiano directory durante l'esecuzione.
rozcietrzewiacz,

@roz Ah, interessante. Quindi suppongo che non causerebbe un problema qui dal momento che sta chiamando qualcosa sul percorso per nome, ma si spezzerebbe altre cose. Grazie
Michael Mrozek

4

Puoi metterlo in cima alla tua sceneggiatura:

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

La variabile bash interna BASH_SOURCE è in realtà una matrice di nomi di percorso. Se lo espandi come una semplice stringa, ad esempio "$ BASH_SOURCE", otterrai il primo elemento, che è il percorso della funzione o script attualmente in esecuzione.

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


2

Stavo provando questi e realpath non ha funzionato per me. La soluzione che ho scelto è:

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

Che ha funzionato bene finora. Vorrei sapere se ci sono potenziali problemi con l'approccio.


1
Buono, ma non segue i collegamenti simbolici. Prova questo:SCRIPT_DIR="$( cd "$(dirname "$( readlink -f ${BASH_SOURCE[0]} )")" >/dev/null 2>&1 && pwd)"
OronNavon il

1

Io uso:

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

Che è POSIX e dovrebbe funzionare fino a quando il dirname di $0non termina in caratteri di nuova riga, non è -e $CDPATHnon è impostato (e forse alcuni altri casi angolari se lo script non è stato cercato $PATH).


0

Uso sempre whichper trovare il percorso completo di un eseguibile dal PERCORSO. Per esempio:

which python

Se lo combini con il dirnamecomando, otterrai:

wp=`which python`
dn=`dirname $wp`
ls $dn
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.