Wie man das richtig macht
Zu allererst immer Ihre Variablen zitieren . Was Sie versuchen zu tun, funktioniert gut, wenn Sie es richtig zitieren:
$ pwd
/home/terdon/foo/\e[92mM@r|< +'|'|_e|\|\|0rth [`-_-"]
$ ls
pullingATerdon
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:
$ bacon="$(realpath pullingATerdon)"
$ echo "$bacon"
/home/terdon/foo/\e[92mM@r|< +'|'|_e|\|\|0rth [`-_-"]/pullingATerdon
$ ls $bacon
ls: cannot access '+'\''|'\''|_e|\|\|0rth': No such file or directory
ls: cannot access '[`-_-"]/pullingATerdon': No such file or directory
'/home/terdon/foo/\e[92mM@r|<':
Das scheitert erwartungsgemäß. Aber wenn wir es jetzt richtig zitieren:
$ ls -l "$bacon"
-rw-r--r-- 1 terdon terdon 0 Mar 14 23:15 '/home/terdon/foo/\e[92mM@r|< +'\''|'\''|_e|\|\|0rth [`-_-"]/pullingATerdon'
Es funktioniert wie erwartet. Und ja, Sie können den Pfad auch in einem (richtigen) Editor öffnen: emacs "$bacon"
funktioniert einwandfrei . OK, so wird vim
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 mit set +x
), wodurch die Shell jeden Befehl druckt, den sie ausführen wird, bevor sie ausgeführt wird. Aktivieren Sie die Debugging-Meldungen der Shell mit set -x
:
$ set -x
$ /bin/ls $bacon
+ ls '/home/terdon/foo/\e[92mM@r|<' '+'\''|'\''|_e|\|\|0rth' '[`-_-"]/pullingATerdon'
ls: cannot access '+'\''|'\''|_e|\|\|0rth': No such file or directory
ls: cannot access '[`-_-"]/pullingATerdon': No such file or directory
'/home/terdon/foo/\e[92mM@r|<':
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:
$ mkdir $(realpath pullingATerdon)
++ realpath pullingATerdon
+ mkdir '/home/terdon/foo/\e[92mM@r|<' '+'\''|'\''|_e|\|\|0rth' '[`-_-"]/pullingATerdon'
mkdir: cannot create directory ‘[`-_-"]/pullingATerdon’: No such file or directory
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|<
:
$ ls -l /home/terdon/foo/
total 8
drwxr-xr-x 2 terdon terdon 4096 Mar 15 00:20 '\e[92mM@r|<'
drwxr-xr-x 3 terdon terdon 4096 Mar 15 00:20 '\e[92mM@r|< +'\''|'\''|_e|\|\|0rth [`-_-"]'
Anschließend wurde ebenfalls erfolgreich ein Verzeichnis erstellt, das +'|'|_e|\|\|0rth
in Ihrem aktuellen Verzeichnis aufgerufen wird :
$ ls -l
total 4
drwxr-xr-x 2 terdon terdon 4096 Mar 15 00:37 '+'\''|'\''|_e|\|\|0rth'
-rw-r--r-- 1 terdon terdon 0 Mar 15 00:36 pullingATerdon
Anschließend wurde versucht, das Verzeichnis zu erstellen [`-_-"]/pullingATerdon
. Dies ist fehlgeschlagen, da mkdir
standardmäßig keine Unterverzeichnisse erstellt werden (dies ist möglich, wenn Sie es ausführen -p
):
$ mkdir baz/bar
mkdir: cannot create directory ‘baz/bar’: No such file or directory
Da Ihre nicht in Anführungszeichen gesetzte Zeichenfolge a enthielt /
, wurde davon mkdir
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:
$ echo "[\`-_-\"]/pullingATerdon" ## some escaping is needed here
+ echo '[`-_-"]/pullingATerdon' ## but it echoes the right thing
[`-_-"]/pullingATerdon ## and matches nothing, so returns itself.
Um dies zu verdeutlichen, geschieht Folgendes, wenn Sie einen Glob angeben, der zu etwas passt:
$ echo [p]* ## any filename starting with a p
pullingATerdon
$ echo "[p]*" ## the string "[p]*"
[p]*
Das nicht zitierte [p*]
wird in die Liste der übereinstimmenden Dateinamen (in diesem Fall nur einer) erweitert und an diese übergeben echo
. 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:
for file in *; do command "$file"; done
Das funktioniert für jeden Dateinamen. Egal was es enthält. In unserem obigen Beispiel hätten Sie Folgendes tun können:
emacs /home/terdon/*92mM*/pullingATerdon
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
vim "$bacon"