Ruft den aktuellen Verzeichnisnamen (ohne vollständigen Pfad) in einem Bash-Skript ab


Antworten:


1115

Keine Notwendigkeit für einen Basisnamen und insbesondere keine Notwendigkeit für eine Unterschale, auf der pwd ausgeführt wird (was eine zusätzliche und teure Gabeloperation hinzufügt ); Die Shell kann dies intern mithilfe der Parametererweiterung tun :

result=${PWD##*/}          # to assign to a variable

printf '%s\n' "${PWD##*/}" # to print to stdout
                           # ...more robust than echo for unusual names
                           #    (consider a directory named -e or -n)

printf '%q\n' "${PWD##*/}" # to print to stdout, quoted for use as shell input
                           # ...useful to make hidden characters readable.

Beachten Sie, dass Sie, wenn Sie diese Technik unter anderen Umständen anwenden (nicht PWD, sondern bei einer anderen Variablen, die einen Verzeichnisnamen enthält), möglicherweise nachfolgende Schrägstriche kürzen müssen. Im Folgenden wird die Extglob-Unterstützung von bash verwendet , um auch mit mehreren nachgestellten Schrägstrichen zu arbeiten:

dirname=/path/to/somewhere//
shopt -s extglob           # enable +(...) glob syntax
result=${dirname%%+(/)}    # trim however many trailing slashes exist
result=${result##*/}       # remove everything before the last / that still remains
printf '%s\n' "$result"

Alternativ ohne extglob:

dirname="/path/to/somewhere//"
result="${dirname%"${dirname##*[!/]}"}" # extglob-free multi-trailing-/ trim
result="${result##*/}"                  # remove everything before the last /

31
Was ist der Unterschied zwischen $ {PWD ## * /} und $ PWD?
Mr_Chimp

24
@Mr_Chimp Ersteres ist eine Parametererweiterungsoperation, die den Rest des Verzeichnisses so trimmt, dass nur der Basisname angegeben wird. Ich habe in meiner Antwort einen Link zur Dokumentation zur Parametererweiterung. Fühlen Sie sich frei, dem zu folgen, wenn Sie Fragen haben.
Charles Duffy

24
@stefgosselin $PWDist der Name einer integrierten Bash-Variablen. Alle integrierten Variablennamen sind in Großbuchstaben angegeben (um sie von lokalen Variablen zu unterscheiden, die immer mindestens ein Kleinbuchstaben haben sollten). result=${PWD#*/}tut nicht bewerten zu /full/path/to/directory; Stattdessen wird nur das erste Element entfernt, wodurch es erstellt wird path/to/directory. Wenn Sie zwei #Zeichen verwenden, wird das Muster gierig und es werden so viele Zeichen wie möglich angezeigt. Weitere Informationen finden Sie auf der Seite zur Parametererweiterung, die in der Antwort verlinkt ist.
Charles Duffy

5
Beachten Sie, dass die Ausgabe von aufgrund von Komplikationen durch symbolische Verknüpfungen pwdnicht immer mit dem Wert von übereinstimmt , ob für bash die Option festgelegt ist usw. Dies war früher besonders unangenehm bei der Handhabung von Verzeichnissen mit automatischer Bereitstellung, bei denen das Aufzeichnen des physischen Pfads anstelle des logischen Pfads einen Pfad ergab, der es dem automatischen Zähler bei Verwendung ermöglichte, das verwendete Verzeichnis spontan zu entfernen. $PWDcd-o physical
Alex North-Keys

3
Nett! Jemand sollte ein Buch für alte Borne Shell-Typen wie mich schreiben. Vielleicht gibt es da draußen einen? Es könnte ein crotchity alt sys Sachen Admin sagen haben , wie „zurück in meinen Tag wir nur shund cshund wenn Sie die Rücktaste wollten Sie das Ganze lesen arbeiten musste sttyman - Seite, und wir hatten eine positive Erfahrung!“
Red Cricket

335

Verwenden Sie das basenameProgramm. Für Ihren Fall:

% basename "$PWD"
bin

20
Ist das nicht der Zweck des basenameProgramms? Was ist falsch an dieser Antwort, außer dass die Anführungszeichen fehlen?
Nacht - Wiedereinstellung Monica

11
@Nacht basenameist in der Tat ein externes Programm , das das Richtige tut, sondern läuft jede für eine Sache bash kann externes Programm tun out-of-the-Box mit nur integrierte Funktionalität albern ist, Auswirkungen auf die Leistung entstehen ( fork(), execve(), wait(), usw.) für kein Grund.
Charles Duffy

3
... als Nebenbei bemerkt, meine Einwände gegen die basenamehier nicht gelten dirname, da dirnamehat Funktionen , die ${PWD##*/}nicht der Fall ist - eine Zeichenkette ohne Schrägstriche zu verwandeln ., zum Beispiel. Während die Verwendung dirnameals externes Tool einen Leistungsaufwand verursacht, verfügt es auch über Funktionen, die dazu beitragen, diese auszugleichen.
Charles Duffy

4
@ LouisMaddox, ein bisschen Kibitzing: Das functionSchlüsselwort ist POSIX-inkompatibel, ohne einen Wert gegenüber der standardisierten Syntax hinzuzufügen, und das Fehlen von Anführungszeichen würde Fehler in Verzeichnisnamen mit Leerzeichen verursachen. wdexec() { "./$(basename "$PWD")"; }könnte eine bevorzugte Alternative sein.
Charles Duffy

28
Sicher ist die Verwendung basenameweniger "effizient". Aber es ist wahrscheinlich mehr effizienter in Bezug auf die Produktivität der Entwickler , weil es einfach ist , im Vergleich zu erinnern an die hässliche bash Syntax. Also, wenn Sie sich daran erinnern, machen Sie es. Ansonsten basenamefunktioniert es genauso gut. Hat jemand jemals die "Leistung" eines Bash-Skripts verbessern und effizienter machen müssen?
usr

139
$ echo "${PWD##*/}"

.


2
@jocap ... außer dass die Verwendung von Echo dort, ohne das Argument zu zitieren, falsch ist . Wenn der Verzeichnisname mehrere Leerzeichen oder ein Tabulatorzeichen enthält, wird er auf ein einzelnes Leerzeichen reduziert. Wenn es ein Platzhalterzeichen hat, wird es erweitert. Richtige Verwendung wäre echo "${PWD##*/}".
Charles Duffy

9
@jocap ... außerdem bin ich mir nicht sicher, ob "Echo" tatsächlich ein legitimer Teil der Antwort ist. Die Frage war, wie man die Antwort bekommt , nicht wie man die Antwort druckt ; Wenn das Ziel beispielsweise darin bestand, es einer Variablen zuzuweisen, name=${PWD##*/}wäre dies richtig und name=$(echo "${PWD##*/}")falsch (im Sinne einer unnötigen Ineffizienz).
Charles Duffy

24

Sie können eine Kombination aus pwd und basename verwenden. Z.B

#!/bin/bash

CURRENT=`pwd`
BASENAME=`basename "$CURRENT"`

echo "$BASENAME"

exit;

18
Bitte nicht. Die Backticks erstellen eine Subshell (also eine Gabeloperation) - und in diesem Fall verwenden Sie sie zweimal ! [Als zusätzliches, wenn auch stilistisches Problem sollten Variablennamen in Kleinbuchstaben geschrieben werden, es sei denn, Sie exportieren sie in die Umgebung oder es handelt sich um einen speziellen, reservierten Fall].
Charles Duffy

11
und als zweiter Stil sollten Quibble-Backtics durch $ () ersetzt werden. noch gabeln aber besser lesbar und mit weniger excaping benötigt.
Jeremy Wall

1
Konventionell werden Umgebungsvariablen (PATH, EDITOR, SHELL, ...) und interne Shell-Variablen (BASH_VERSION, RANDOM, ...) vollständig aktiviert. Alle anderen Variablennamen sollten klein geschrieben sein. Da bei Variablennamen zwischen Groß- und Kleinschreibung unterschieden wird, wird durch diese Konvention vermieden, dass Umgebungsvariablen und interne Variablen versehentlich überschrieben werden.
Rany Albeg Wein

2
Kommt auf die Konvention an. Man könnte argumentieren, dass alle Shell-Variablen Umgebungsvariablen sind (abhängig von der Shell), und daher sollten alle Shell-Variablen in Großbuchstaben angegeben werden. Jemand anderes könnte basierend auf dem Geltungsbereich argumentieren - globale Variablen sind Großbuchstaben, während lokale Variablen Kleinbuchstaben sind und diese alle global sind. Ein anderer könnte argumentieren, dass das Festlegen von Variablen in Großbuchstaben einen zusätzlichen Kontrast zu den Befehlen darstellt, die Shell-Skripte verunreinigen, bei denen es sich ebenfalls um kurze, aber aussagekräftige Kleinbuchstaben handelt. Ich kann einem dieser Argumente zustimmen oder auch nicht, aber ich habe alle drei in Gebrauch gesehen. :)
dannysauer

17

Wie wäre es mit grep:

pwd | grep -o '[^/]*$'

pwd | xargs basename
Ich

8

Ich mag die ausgewählte Antwort (Charles Duffy), aber seien Sie vorsichtig, wenn Sie sich in einem verknüpften Verzeichnis befinden und den Namen des Zielverzeichnisses möchten. Leider glaube ich nicht, dass dies in einem einzelnen Parametererweiterungsausdruck möglich ist, vielleicht irre ich mich. Das sollte funktionieren:

target_PWD=$(readlink -f .)
echo ${target_PWD##*/}

Um dies zu sehen, ein Experiment:

cd foo
ln -s . bar
echo ${PWD##*/}

meldet "bar"

DIRNAME

So zeigen Sie die führenden Verzeichnisse eines Pfads an (ohne dass ein Fork-Exec von / usr / bin / dirname erforderlich ist):

echo ${target_PWD%/*}

Dies wird zB foo / bar / baz -> foo / bar transformieren


5
Leider readlink -fhandelt es sich um eine GNU-Erweiterung, die auf den BSDs (einschließlich OS X) nicht verfügbar ist.
Xiong Chiamiov

8
echo "$PWD" | sed 's!.*/!!'

Wenn Sie die Bourne-Shell verwenden oder ${PWD##*/}nicht verfügbar sind.


4
Zu Ihrer Information, ${PWD##*/}ist POSIX sh - jedes moderne / bin / sh (einschließlich Armaturenbrett, Asche usw.) unterstützt es; Um Bourne auf einer aktuellen Box zu treffen, müssen Sie sich auf einem leicht veralteten Solaris-System befinden. Darüber hinaus - echo "$PWD"; Das Weglassen der Anführungszeichen führt zu Fehlern (wenn der Verzeichnisname Leerzeichen, Platzhalterzeichen usw. enthält).
Charles Duffy

1
Ja, ich habe ein altes Solaris-System verwendet. Ich habe den Befehl aktualisiert, um Anführungszeichen zu verwenden.
Anomalie

7

Dieser Thread ist großartig! Hier ist noch ein Geschmack:

pwd | awk -F / '{print $NF}'

5

Überraschenderweise erwähnte niemand diese Alternative, die nur eingebaute Bash-Befehle verwendet:

i="$IFS";IFS='/';set -f;p=($PWD);set +f;IFS="$i";echo "${p[-1]}"

Als zusätzlichen Bonus können Sie den Namen des übergeordneten Verzeichnisses leicht erhalten mit:

[ "${#p[@]}" -gt 1 ] && echo "${p[-2]}"

Diese funktionieren unter Bash 4.3-alpha oder neuer.


überraschend? nur ein Scherz, aber andere sind viel kürzer und leichter zu merken
Codewandler

Das ist ziemlich lustig = P Hatte vorher noch nichts von $ IFS (internes Feldtrennzeichen) gehört. Meine Bash war zu alt, kann sie aber hier testen: jdoodle.com/test-bash-shell-script-online
Stan Kurdziel

5

Verwenden:

basename "$PWD"

ODER

IFS=/ 
var=($PWD)
echo ${var[-1]} 

Schalten Sie den internen Dateinamen-Separator (IFS) wieder auf Leerzeichen.

IFS= 

Nach dem IFS steht ein Leerzeichen.


4
basename $(pwd)

oder

echo "$(basename $(pwd))"

2
Um korrekt zu sein, sind mehr Anführungszeichen pwderforderlich. Die Ausgabe von wird vor der Übergabe an Zeichenfolgen aufgeteilt und global erweitert basename.
Charles Duffy

Also basename "$(pwd)"- obwohl das im Vergleich zu just sehr ineffizient ist basename "$PWD", was selbst ineffizient ist im Vergleich zur Verwendung einer Parametererweiterung, anstatt überhaupt aufzurufen basename.
Charles Duffy

4

Für die Findjockeys da draußen wie mich:

find $PWD -maxdepth 0 -printf "%f\n"

Ändern Sie das $PWDin "$PWD", um ungewöhnliche Verzeichnisnamen korrekt zu behandeln.
Charles Duffy

3

Ich benutze dies normalerweise in sh-Skripten

SCRIPTSRC=`readlink -f "$0" || echo "$0"`
RUN_PATH=`dirname "${SCRIPTSRC}" || echo .`
echo "Running from ${RUN_PATH}"
...
cd ${RUN_PATH}/subfolder

Sie können dies verwenden, um Dinge zu automatisieren ...


readlink: illegal option -- f usage: readlink [-n] [file ...]

2

Unten funktioniert grep with regex auch,

>pwd | grep -o "\w*-*$"

3
Es funktioniert nicht, wenn der Verzeichnisname "-" Zeichen enthält.
Daniula

1

Benutz einfach:

pwd | xargs basename

oder

basename "`pwd`"

2
Dies ist in jeder Hinsicht eine schlechtere Version der Antwort, die Arkady zuvor gegeben hat ( stackoverflow.com/a/1371267/14122 ): Die xargsFormulierung ist ineffizient und fehlerhaft, wenn Verzeichnisnamen wörtliche Zeilenumbrüche oder Anführungszeichen enthalten, und die zweite Formulierung ruft den pwdBefehl auf in einer Unterschale, anstatt dasselbe Ergebnis über eine integrierte variable Erweiterung abzurufen.
Charles Duffy

@ CharlesDuffy Trotzdem ist es eine gültige und praktische Antwort auf die Frage.
Bachph

1

Wenn Sie nur das aktuelle Verzeichnis in der Bash-Eingabeaufforderungsregion anzeigen möchten, können Sie die .bashrcDatei in bearbeiten ~. Ändern Sie \wzu \Win der Zeile:

PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

Ausführen source ~/.bashrcund es wird nur der Verzeichnisname in der Eingabeaufforderungsregion angezeigt.

Ref: /superuser/60555/show-only-current-directory-name-not-full-path-on-bash-prompt


0

Sie können das Dienstprogramm basename verwenden, mit dem alle Präfixe, die mit / enden, und das Suffix (falls in der Zeichenfolge vorhanden) aus der Zeichenfolge gelöscht und das Ergebnis in der Standardausgabe gedruckt werden.

$basename <path-of-directory>

0

Ich bevorzuge stark die Verwendung gbasename, die Teil von GNU Coreutils ist.


Zu Ihrer Information, es kommt nicht mit meiner Ubuntu-Distribution.
Katastic Voyage

@ KatasticVoyage, es ist dort auf Ubuntu, es heißt nur basenamedort. Es wird normalerweise nur gbasenameunter MacOS und anderen Plattformen aufgerufen , die ansonsten mit einem Nicht-GNU-Basisnamen geliefert werden.
Charles Duffy

-1

Die folgenden Befehle führen dazu, dass Ihr aktuelles Arbeitsverzeichnis in einem Bash-Skript gedruckt wird.

pushd .
CURRENT_DIR="`cd $1; pwd`"
popd
echo $CURRENT_DIR

2
(1) Ich bin nicht sicher, wo wir sicherstellen, dass die Argumentliste $1das aktuelle Arbeitsverzeichnis enthält. (2) Das pushdund hat popdhier keinen Zweck, da alles in Backticks in einer Subshell ausgeführt wird - es kann also zunächst keinen Einfluss auf das Verzeichnis der übergeordneten Shell haben. (3) Die Verwendung "$(cd "$1"; pwd)"wäre sowohl lesbar als auch widerstandsfähiger gegenüber Verzeichnisnamen mit Leerzeichen.
Charles Duffy
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.