Ruft den letzten Verzeichnisnamen / Dateinamen in einem Dateipfadargument in Bash ab

227

Ich versuche, einen Post-Commit-Hook für SVN zu schreiben, der auf unserem Entwicklungsserver gehostet wird. Mein Ziel ist es, eine Kopie des festgeschriebenen Projekts automatisch in das Verzeichnis auszuchecken, in dem es auf dem Server gehostet wird. Ich muss jedoch nur das letzte Verzeichnis in der an das Skript übergebenen Verzeichniszeichenfolge lesen können, um in dasselbe Unterverzeichnis auschecken zu können, in dem unsere Projekte gehostet werden.

Wenn ich beispielsweise ein SVN-Commit für das Projekt "example" durchführe, erhält mein Skript als erstes Argument "/ usr / local / svn / repos / example". Ich muss nur "Beispiel" vom Ende der Zeichenfolge entfernen und es dann mit einer anderen Zeichenfolge verknüpfen, damit ich zu "/ server / root / example" auschecken und die Änderungen sofort live sehen kann.

TJ L.
quelle

Antworten:

344

basename entfernt das Verzeichnispräfix eines Pfads:

$ basename /usr/local/svn/repos/example
example
$ echo "/server/root/$(basename /usr/local/svn/repos/example)"
/server/root/example
etw
quelle
2
Basisname ist definitiv das, wonach ich suche. Wie kann der Basisname eines Arguments in einer Variablen gespeichert werden? ZBSUBDIR="/path/to/whatever/$(basename $1)"
TJ L
5
@ tj111: klingt wie ist nein $1oder $1ist leer
etw
Wenn Sie Befehle umbrechen, ist der Basisname leider keine gute Idee. nur etwas zu beachten
dtc
97

Der folgende Ansatz kann verwendet werden, um einen beliebigen Pfad eines Pfadnamens abzurufen:

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

Ausgabe:

c
b
a
Jingguo Yao
quelle
1
funktioniert nicht mit Pfaden, die Leerzeichen haben ... Sie können das mit Anführungszeichen überwinden ... was irgendwie funktioniertecho "$(basename "$(dirname "$pathname")")"
Ray Foss
75

Bash kann den letzten Teil eines Pfades abrufen, ohne den externen aufrufen zu müssen basename:

subdir="/path/to/whatever/${1##*/}"
Bis auf weiteres angehalten.
quelle
2
Auf meinem Mac ist die Verwendung der Teilstring-Notation mehr als eine Größenordnung schneller als der Name / Basisname, wenn Sie mit jeder der wenigen tausend Dateien etwas Triviales tun.
George
1
d=/home/me/somefolder;subdir="/$d/${1##*/}"Am Ende hatte ich so etwas wie //home/me/somefolder//das $ d, das tatsächlich aus einer Schleife stammt. Die for d in $(find $SOMEFOLDER -maxdepth 1 -type d);Verwendung subdir=$(basename $d)funktioniert wie erwartet.
Buttle Butkus
1
@ButtleButkus: Sie sollten verwenden, whileanstatt forüber die Ausgabe von find( find -print0 | xargs -0ist besser) zu iterieren, oder Globbing verwenden: for d in $SOMEFOLDER/*/(Der endgültige Schrägstrich funktioniert wie -type d- Sie können **in Bash 4 für die Rekursion verwenden, wenn Sie shopt -s globstar, aber eine Meldung "Argumentliste zu lang" ist möglich). Beachten Sie, dass der ${1}Teil des Befehls das erste Argument eines Skripts oder einer Funktion darstellt. Möglicherweise müssen Sie eine ${d##*/}andere Variablen- oder Argumentspezifikation verwenden oder sicherstellen, dass ein Argument übergeben wird.$1
Bis auf weiteres angehalten.
2
@ TennisWilliamson Vielen Dank für das Teilen . Für alle zukünftigen Leser, die sich fragen, warum es nicht funktioniert oder ich der einzige Dumme hier draußen bin 😂. Die obige Antwort geht davon aus, dass sie $1enthält the path from which last component is to be taken out. Ich habe diesen Teil verpasst. Mein Anwendungsfall: target_path='/home/user/dir1/dir2/dir3/'; target_path="${target_path%/}"; last_component=${target_path##*/}; echo $last_component- Works 😉
Vinay Vissh
2
Hier finden Sie eine Erklärung, wie und warum dies ${1##*/} funktioniert: unix.stackexchange.com/a/171786/15070
Matthew