Récupère le dernier nom / nom de fichier dans un argument de chemin de fichier dans Bash

228

J'essaie d'écrire un hook post-commit pour SVN, qui est hébergé sur notre serveur de développement. Mon objectif est d'essayer d'extraire automatiquement une copie du projet validé dans le répertoire où il est hébergé sur le serveur. Cependant, je dois être capable de lire uniquement le dernier répertoire de la chaîne de répertoire passée au script afin de passer au même sous-répertoire où nos projets sont hébergés.

Par exemple, si je fais un commit SVN dans le projet "example", mon script obtient "/ usr / local / svn / repos / example" comme premier argument. J'ai besoin de simplement "exemple" à la fin de la chaîne, puis de le concaténer avec une autre chaîne afin que je puisse passer à "/ server / root / example" et voir les changements en direct immédiatement.

TJ L
la source

Réponses:

344

basename supprime le préfixe de répertoire d'un chemin:

$ basename /usr/local/svn/repos/example
example
$ echo "/server/root/$(basename /usr/local/svn/repos/example)"
/server/root/example
qch
la source
2
nom de base est certainement ce que je recherche. Comment obtenir le nom de base d'un argument stocké dans une variable? Par exempleSUBDIR="/path/to/whatever/$(basename $1)"
TJ L
5
@ tj111: sonne comme non $1ou $1est vide
sth
malheureusement, si vous encapsulez des commandes, le nom de base n'est pas une bonne idée. juste quelque chose à garder à l'esprit
dtc
98

L'approche suivante peut être utilisée pour obtenir n'importe quel chemin d'un nom de chemin:

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

Production:

c
b
a
Jingguo Yao
la source
1
ne fonctionne pas avec les chemins qui ont des espaces ... vous pouvez surmonter cela avec des guillemets ... qui fonctionne en quelque sorteecho "$(basename "$(dirname "$pathname")")"
Ray Foss
75

Bash peut obtenir la dernière partie d'un chemin sans avoir à appeler l'externe basename:

subdir="/path/to/whatever/${1##*/}"
En pause jusqu'à nouvel ordre.
la source
2
Sur mon Mac, l'utilisation de la notation de sous-chaîne est plus d'un ordre de grandeur plus rapide que dirname / basename dans le cas où vous faites quelque chose de trivial pour chacun des quelques milliers de fichiers.
George
1
d=/home/me/somefolder;subdir="/$d/${1##*/}"Je me suis retrouvé avec quelque chose comme //home/me/somefolder//le $ d vient en fait d'une boucle for d in $(find $SOMEFOLDER -maxdepth 1 -type d);utilisant Works subdir=$(basename $d)fonctionne comme prévu.
Buttle Butkus
1
@ButtleButkus: Vous devriez utiliser whileau lieu de forparcourir la sortie de find( find -print0 | xargs -0est mieux) ou utiliser la globalisation: for d in $SOMEFOLDER/*/(la barre oblique finale fonctionne comme -type d- vous pouvez utiliser **dans Bash 4 pour la récursion si vous shopt -s globstar, mais un message "Liste d'arguments trop longue" est possible). Notez que la ${1}partie de la commande représente le premier argument d'un script ou d'une fonction. Vous devrez peut-être utiliser ${d##*/}une autre spécification de variable ou d'argument ou vous assurer qu'un argument est transmis$1
pause jusqu'à nouvel ordre.
2
@DennisWilliamson Merci beaucoup pour le partage . Pour tous les futurs lecteurs qui commencent à se demander pourquoi cela ne fonctionne pas ou je suis le seul stupide ici 😂. La réponse ci-dessus suppose que $1contient the path from which last component is to be taken out. J'ai raté cette partie. Mon cas d'utilisation: target_path='/home/user/dir1/dir2/dir3/'; target_path="${target_path%/}"; last_component=${target_path##*/}; echo $last_component- 😉 Œuvres
Vinay Vissh
2
Voir ici pour une explication de comment et pourquoi ${1##*/} fonctionne: unix.stackexchange.com/a/171786/15070
Matthew