Ottieni l'ultimo dirname / nomefile in un argomento percorso file in Bash


228

Sto cercando di scrivere un hook post-commit per SVN, che è ospitato sul nostro server di sviluppo. Il mio obiettivo è provare a verificare automaticamente una copia del progetto impegnato nella directory in cui è ospitato sul server. Tuttavia, devo essere in grado di leggere solo l'ultima directory nella stringa di directory passata allo script per effettuare il checkout nella stessa sottodirectory in cui sono ospitati i nostri progetti.

Ad esempio, se faccio un commit SVN per il progetto "esempio", il mio script ottiene "/ usr / local / svn / repos / example" come primo argomento. Ho bisogno di ottenere solo un "esempio" dalla fine della stringa e quindi concatolarlo con un'altra stringa in modo da poter effettuare il checkout a "/ server / root / example" e vedere immediatamente le modifiche.

Risposte:


344

basename rimuove il prefisso della directory di un percorso:

$ basename /usr/local/svn/repos/example
example
$ echo "/server/root/$(basename /usr/local/svn/repos/example)"
/server/root/example

2
basename è sicuramente quello che sto cercando. Come si può ottenere il nome di base di un argomento archiviato in una variabile? Ad esempioSUBDIR="/path/to/whatever/$(basename $1)"
TJ L

5
@ tj111: sembra che sia no $1, oppure $1è vuoto
sth

sfortunatamente, se si avvolgono i comandi, basename non è una buona idea. solo qualcosa da tenere a mente
dtc

98

Il seguente approccio può essere utilizzato per ottenere qualsiasi percorso di un percorso:

some_path=a/b/c
echo $(basename $some_path)
echo $(basename $(dirname $some_path))
echo $(basename $(dirname $(dirname $some_path)))

Produzione:

c
b
a

1
non funziona con percorsi che hanno spazi ... puoi superarlo con le virgolette ... che in qualche modo funzionaecho "$(basename "$(dirname "$pathname")")"
Ray Foss

75

Bash può ottenere l'ultima parte di un percorso senza dover chiamare l'esterno basename:

subdir="/path/to/whatever/${1##*/}"

2
Sul mio Mac, usare la notazione di sottostringa è più che dell'ordine di grandezza più veloce di dirname / basename per il caso in cui stai facendo qualcosa di banale per ognuna delle poche migliaia di file.
George,

1
d=/home/me/somefolder;subdir="/$d/${1##*/}"Ho finito con qualcosa come //home/me/somefolder//$ d in realtà proviene da un ciclo for d in $(find $SOMEFOLDER -maxdepth 1 -type d);usando subdir=$(basename $d)funziona come previsto.
Buttle Butkus,

1
@ButtleButkus: dovresti usare whileinvece di scorrere forl'output di find( find -print0 | xargs -0è meglio) o usare il globbing: for d in $SOMEFOLDER/*/(la barra finale funziona come -type d- puoi usare **in Bash 4 per ricorsione se tu shopt -s globstar, ma un messaggio "Elenco argomenti troppo lungo" è possibile). Si noti che la ${1}parte del comando rappresenta il primo argomento di uno script o di una funzione. Potrebbe essere necessario utilizzare ${d##*/}o qualche altra variabile o specifica dell'argomento o accertarsi che un argomento sia passato$1
Sospeso fino a nuovo avviso.

2
@DennisWilliamson Grazie mille per la condivisione . Per i futuri lettori che iniziano a chiedersi perché non funziona o sono l'unico stupido qui fuori 😂. La risposta sopra presuppone che $1contenga the path from which last component is to be taken out. Mi mancava quella parte. Il mio caso d'uso: target_path='/home/user/dir1/dir2/dir3/'; target_path="${target_path%/}"; last_component=${target_path##*/}; echo $last_component- Opere 😉
Vinay Vissh

2
Vedi qui per una spiegazione di come e perché ${1##*/} funziona: unix.stackexchange.com/a/171786/15070
Matteo
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.