Wie teile ich die Variable $ 0 auf, um Verzeichnis- und relative Pfade in bash zu finden?

10

Die Variable $ 0 enthält die Pfadinformationen des Skripts.

  • Wie kann ich die Pfadinformationen in absoluten Pfad ändern? Ich meine, wie man ~,., .. oder ähnliches verarbeitet?
  • Wie kann ich die Pfadinformationen in Verzeichnis und Dateinamen aufteilen?

Ich könnte Python / Perl dafür verwenden, aber ich möchte wenn möglich Bash verwenden.

prosseek
quelle
Was versuchst du zu erreichen? Übrigens. Wenn ich ein Skript mit ~ / foo.sh aufrufe, wird ~ mit meiner Bash-Version (GNU Bash, Version 4.1.5 (2) -release- (x86_64-unknown-linux-gnu)) in mein Home-Verzeichnis für $ 0 erweitert
echox

Antworten:

17

Sie müssen keine Dinge wie verarbeiten ~, die Shell erledigt das für Sie. Aus diesem Grund können Sie ~/filenamean jedes Skript oder Programm übergeben, und es funktioniert - all diese Programme behandeln ~sich nicht selbst, Ihre Shell konvertiert das Argument in /home/username/filenameund übergibt es stattdessen an das Programm:

$ echo ~/filename
/home/mrozekma/filename

Wenn Sie einen kanonischen Dateinamen benötigen (der keine Dinge wie enthält ..), verwenden Sie realpath(danke Neil ):

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

Verwenden Sie zum Aufteilen des Pfads in Verzeichnisname und Dateiname dirnameund basename:

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

$ basename /foo/bar/baz
baz
Michael Mrozek
quelle
Ich denke du meinst Realpath, nicht Readlink. readlink funktioniert in der allgemeinen Situation nicht, dh wenn der Link einen relativen Pfad verwendet und Sie sich nicht im selben Verzeichnis wie der Link befinden.
Neil Mayhew
@Neil realpathist besser, readlinkscheint aber zu funktionieren, wenn ich es versuche; Kennen Sie ein Beispiel, bei dem es fehlschlägt?
Michael Mrozek
1
cd /tmp; touch foo; ln -s foo bar; cd; readlink /tmp/bar. Dies kehrt zurück foound realpathkehrt zurück /tmp/foo, was Sie wollen.
Neil Mayhew
1
@Neil, @Michael: readlink -f(Anmerkung -f) ist fast gleichbedeutend mit realpathund es ist portabler: readlink -fin GNU-Coreutils und existiert auch auf einigen anderen Systemen; realpathist separat verpackt und darf nicht installiert werden (zB hängen nur 5 nicht so übliche Pakete in Ubuntu 10.04 oder Debian Lenny davon ab).
Gilles 'SO - hör auf böse zu sein'
@ Gilles: guter Punkt. Danke für die Erinnerung an realpath -f.
Neil Mayhew
5

Die Verwendung von Dirname und Basename, wie von Michael erwähnt, sollte der sicherste Weg sein, um das zu bekommen, was Sie wollen.

Wenn Sie dies wirklich mit "bash only tools" tun möchten, können Sie die Parametersubstitution verwenden:

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.

Dieses Beispiel stammt direkt aus dem Advanced Bash Scripting Guide, das einen Blick wert ist.

Die Erklärung ist ziemlich einfach:

$ {var # Pattern} Entfernen Sie aus $ var den kürzesten Teil von $ Pattern, der dem Frontend von $ var entspricht. $ {var ## Pattern} Entfernen Sie aus $ var den längsten Teil von $ Pattern, der mit dem Frontend von $ var übereinstimmt.

Betrachten Sie das Muster wie einen regulären Ausdruck und den #oder ##als eine Art gierigen / nicht gierigen Modifikator.

Dies kann nützlich sein, wenn Sie einige kompliziertere Extraktionen eines Pfadteils durchführen müssen.

Echox
quelle
5
Passen Sie auf, wenn Sie ${...##...}und Freunde verwenden dirnameund nicht, basenamedass sie nicht in allen Fällen funktionieren. Zum Beispiel beides ${0##*/}und ${0%/*}erweitern auf dasselbe, als $0ob $0es kein a enthält /.
Gilles 'SO - hör auf böse zu sein'
@ Gilles Ich verstehe, warum ${0%/*}ist keine gute Alternative zu dirname. Was ist jedoch falsch daran, ${0##*/}statt zu verwenden basename?
Toxalot
@toxalot In diesem Fall besteht das einzige Problem darin, wann $0ein Verzeichnisname mit einem nachgestellten Zeichen angegeben wird /. Aber ich bedauere meinen Rat, weil dirnamees nicht besser geht.
Gilles 'SO - hör auf böse zu sein'
2

realpath ist ein Befehl, der Ihnen den tatsächlichen Pfad angibt (entfernt .. und symbolische Links usw.)

Es ist Standard bei FreeBSD. Nach dieser Diskussion ist es auch für Linux verfügbar:

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

Diese Diskussion bietet auch eine Bash-Lösung:

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

quelle
1
Genau so etwas funktioniert normalerweise: MYDIR = "$ (cd $ (dirname" $ ​​0 "); pwd)"
Kevin Cantu