realpath
und readlink
absolute Pfade zurückgeben:
+akiva@X230:~$ realpath ZannaIsAwesome
/home/akiva/ZannaIsAwesome
Ein solcher Weg ist leicht zu bewältigen. So etwas wird jedoch einige Probleme haben:
Zum Beispiel:
Ein Name wie dieser muss also bereinigt werden, um ihn anderen Befehlen zuzuführen. Ein Anwendungsfall könnte ungefähr so aussehen:
+a@X230:~/\e[92mM@r|< $hu+'|'|_e|\|\|0rth [`-_-"]$ bacon=$(realpath pullingATerdon)
+a@X230:~$ vim $bacon
Unnötig zu sagen, vim $bacon
wird nicht wie erwartet funktionieren.
Was kann ich tun, um diesen absoluten Pfad zu bereinigen, damit er mit anderen Befehlen funktioniert?
command-line
bash
paths
Akiva
quelle
quelle
vim "$bacon"
Antworten:
Wie man das richtig macht
Zu allererst immer Ihre Variablen zitieren . Was Sie versuchen zu tun, funktioniert gut, wenn Sie es richtig zitieren:
Ich habe den seltsamen Dateinamen, den Sie gewählt haben ( obwohl ich keine Ahnung habe, warum Sie ihn gewählt haben ), aus Gründen der Konsistenz beibehalten .
Weisen wir
pullingATerdon
nun einer Variablen den Pfad zu und versuchen dann, die Datei zu öffnen:Das scheitert erwartungsgemäß. Aber wenn wir es jetzt richtig zitieren:
Es funktioniert wie erwartet. Und ja, Sie können den Pfad auch in einem (richtigen) Editor öffnen:
emacs "$bacon"
funktioniert einwandfrei . OK, so wirdvim
und alles andere. Ihre Wahl des Herausgebers ist zwar unglücklich, aber nicht relevant.Warum deine gescheitert ist
Eine schnelle Möglichkeit, um zu verfolgen, was in Ihrem Fall tatsächlich passiert ist, ist die Verwendung
set -x
(deaktivieren Sie es erneut mitset +x
), wodurch die Shell jeden Befehl druckt, den sie ausführen wird, bevor sie ausgeführt wird. Aktivieren Sie die Debugging-Meldungen der Shell mitset -x
:Das zeigt uns, dass
ls
mit drei separaten Argumenten ausgeführt wurde :'/home/terdon/foo/\e[92mM@r|<'
,'+'\''|'\''|_e|\|\|0rth'
und'[`-_-"]/pullingATerdon'
. Dies liegt daran, dass die Shell Wortaufteilung und Glob-Erweiterung für nicht zitierte Zeichenfolgen ausführt . In diesem Fall besteht das Problem in der Wortaufteilung, da die Shell die Leerzeichen im Pfad sah und jede durch Leerzeichen getrennte Zeichenfolge als separates Argument las.Das
mkdir
Beispiel ist etwas anders, aber das liegt daran, dass Sie uns die Fehlermeldung vom zweiten Aufruf des Befehls anzeigen. Ich denke, Sie haben es einmal versucht und es dann ein zweites Mal ausgeführt, um die Ausgabe für Ihre Frage zu erhalten. Das erste Mal, als Sie es ausgeführt haben, hätte es so ausgesehen:Auch hier wird versucht, drei Verzeichnisse zu erstellen, nicht eines, da die Wörter geteilt werden. Zunächst wurde das Verzeichnis (erfolgreich) erstellt
/home/terdon/foo/\e[92mM@r|<
:Anschließend wurde ebenfalls erfolgreich ein Verzeichnis erstellt, das
+'|'|_e|\|\|0rth
in Ihrem aktuellen Verzeichnis aufgerufen wird :Anschließend wurde versucht, das Verzeichnis zu erstellen
[`-_-"]/pullingATerdon
. Dies ist fehlgeschlagen, damkdir
standardmäßig keine Unterverzeichnisse erstellt werden (dies ist möglich, wenn Sie es ausführen-p
):Da Ihre nicht in Anführungszeichen gesetzte Zeichenfolge a enthielt
/
, wurde davonmkdir
ausgegangen, dass es sich um einen Pfad aus zwei Verzeichnissen handelt, und versucht, das oberste zu finden, und ist fehlgeschlagen.Deshalb ist es gescheitert, aber was passiert ist, ist komplizierter. Die von Ihnen verwendete Zeichenfolge ist tatsächlich ein Shell-Glob, insbesondere ein Glob-Bereich , der mit allen Dateien im aktuellen Verzeichnis übereinstimmt, deren Name eines der 5 Zeichen
`
ist-
,_
oder"
. Da Sie keine solchen Dateien in Ihrem aktuellen Verzeichnis haben, stimmt der Glob mit nichts überein und gibt sich wie das Standardverhalten in bash selbst zurück:Um dies zu verdeutlichen, geschieht Folgendes, wenn Sie einen Glob angeben, der zu etwas passt:
Das nicht zitierte
[p*]
wird in die Liste der übereinstimmenden Dateinamen (in diesem Fall nur einer) erweitert und an diese übergebenecho
. Ein weiterer Grund, warum Sie alle Dinge zitieren sollten.Der tatsächliche Fehler, den Sie anzeigen, tritt beim zweiten Ausführen des Befehls auf und schlägt beim ersten Schritt beim Erstellen fehl
/home/terdon/foo/\e[92mM@r|<
, da der vorherige Aufruf dieses Verzeichnis bereits erstellt hat.Verwenden Sie im Allgemeinen immer Shell-Globs, wenn Sie mit beliebigen Dateinamen arbeiten. Dinge wie dieses:
Das funktioniert für jeden Dateinamen. Egal was es enthält. In unserem obigen Beispiel hätten Sie Folgendes tun können:
Jeder Glob, der die Zieldatei eindeutig identifiziert, reicht aus. Auf diese Weise müssen Sie sich keine Gedanken über die Sonderzeichen machen und können die Shell einfach damit umgehen lassen.
Einige nützliche Referenzen:
Wie kann ich Dateinamen finden und sicher behandeln, die Zeilenumbrüche, Leerzeichen oder beides enthalten? : Eine der FAQs im exzellenten Grey Cat's Wiki.
Sicherheitsauswirkungen des Vergessens, eine Variable in Bash / POSIX-Shells zu zitieren : der gleiche Beitrag, auf den ich am Anfang dieser Antwort verwiesen habe. Eine großartige und sehr detaillierte Erklärung aller Dinge, die schief gehen könnten, wenn Sie Ihre Shell-Variablen nicht richtig zitieren.
Warum verschluckt sich mein Shell-Skript an Leerzeichen oder anderen Sonderzeichen? : alles, was Sie schon immer über den Umgang mit beliebigen Dateinamen in der Shell wissen wollten.
Wann ist eine doppelte Anführungszeichen erforderlich? : Mehr über Anführungszeichen und Variablen und insbesondere die wenigen Fälle, in denen Sie sie nicht zitieren müssen
quelle