Come divido la variabile $ 0 per trovare directory e relativi percorsi in bash?


10

La variabile $ 0 contiene le informazioni sul percorso dello script.

  • Come posso modificare le informazioni sul percorso in percorso assoluto? Intendo come elaborare ~,., .. o simili?
  • Come posso dividere le informazioni sul percorso in directory e nome file?

Potrei usare python / perl per questo, ma voglio usare bash se possibile.


cosa stai cercando di ottenere? btw. chiamare uno script con ~ / foo.sh espande ~ nella mia directory home per $ 0 con la mia versione bash (GNU bash, versione 4.1.5 (2) -release- (x86_64-unknown-linux-gnu))
echox

Risposte:


17

Non hai bisogno di elaborare cose come ~, la shell lo fa per te. Ecco perché puoi passare ~/filenamea qualsiasi script o programma e funziona: tutti quei programmi non si gestiscono da ~soli, la tua shell converte l'argomento in /home/username/filenamee lo passa invece al programma:

$ echo ~/filename
/home/mrozekma/filename

Se hai bisogno di un nome file canonico (uno che non include cose del genere ..), usa realpath(grazie Neil ):

$ realpath ~/../filename
/home/filename

Per quanto riguarda la divisione del percorso in nome directory e nome file, utilizzare dirnamee basename:

$ dirname /foo/bar/baz
/foo/bar

$ basename /foo/bar/baz
baz

Penso che intendi realpath, non readlink. readlink non funzionerà nella situazione comune, ovvero quando il collegamento utilizza un percorso relativo e non ci si trova nella stessa directory del collegamento.
Neil Mayhew,

@Neil realpathè meglio, ma readlinksembra funzionare quando lo provo; conosci un esempio in cui fallisce?
Michael Mrozek

1
cd /tmp; touch foo; ln -s foo bar; cd; readlink /tmp/bar. Questo ritorna fooe realpathritorna /tmp/foo, che è quello che vuoi.
Neil Mayhew,

1
@Neil, @Michael: readlink -f(nota -f) è quasi equivalente a realpath, ed è più portabile: readlink -fnei coreutils GNU ed esiste anche su alcuni altri sistemi; realpathè confezionato separatamente e potrebbe non essere installato (ad esempio solo 5 pacchetti non molto comuni dipendono da esso in Ubuntu 10.04 o Debian lenny).
Gilles 'SO- smetti di essere malvagio' il

@Gilles: buon punto. Grazie per il promemoria su realpath -f.
Neil Mayhew,

5

Usare dirname e basename come menzionato da Michael dovrebbe essere il modo più sicuro per ottenere quello che vuoi.

Ad ogni modo se vuoi davvero farlo con "strumenti solo bash" puoi usare la sostituzione dei parametri:

echo `basename $PWD`        # Basename of current working directory.
echo "${PWD##*/}"           # Basename of current working directory.
echo
echo `basename $0`          # Name of script.
echo $0                     # Name of script.
echo "${0##*/}"             # Name of script.
echo
filename=test.data
echo "${filename##*.}"      # data
                            # Extension of filename.

Questo esempio è preso direttamente dalla Guida di scripting Advanced Bash che vale la pena dare un'occhiata.

La spiegazione è piuttosto semplice:

$ {var # Pattern} Rimuovi da $ var la parte più corta di $ Pattern che corrisponde al front-end di $ var. $ {var ## Pattern} Rimuovi da $ var la parte più lunga di $ Pattern che corrisponde al front-end di $ var.

Guarda lo schema come un po 'di regex e il #o ##come una sorta di modificatore avido / non avido.

Questo potrebbe essere utile se dovrai fare alcune estrazioni più complicate di una parte dei percorsi.


5
Fai attenzione quando usi ${...##...}e gli amici piuttosto che dirnamee basenameche non funzionano in tutti i casi. Ad esempio entrambi ${0##*/}e si ${0%/*}espande allo stesso modo $0se $0non contiene a /.
Gilles 'SO- smetti di essere malvagio' il

@Gilles Capisco perché ${0%/*}non è una buona alternativa a dirname. Tuttavia, cosa c'è di sbagliato nell'usare ${0##*/}invece di basename?
Toxalot

@toxalot Per questo, l'unico problema è quando $0è un nome di directory con un finale /. Ma mi pento del mio consiglio, perché dirnamenon fa niente di meglio.
Gilles 'SO- smetti di essere malvagio' il

2

realpath è un comando che ti dice il percorso reale (rimuove .. e collegamenti simbolici ecc.)

È standard con FreeBSD. Secondo questa discussione è disponibile anche per Linux:

http://www.unix.com/shell-programming-scripting/89294-geting-real-path.html

Questa discussione offre anche una soluzione bash:

$ bash -c "cd /foo/../bar/ ; pwd"

1
Esattamente, qualcosa del genere di solito funziona: MYDIR = "$ (cd $ (dirname" $ ​​0 "); pwd)"
Kevin Cantu
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.