Ich habe den Befehl cd C:\foo\bar\
von PowerShell nach Cygwin kopiert und albern erwartet, dass er ausgeführt wird. Ich versuche nun einen Wechsel zu laufen alle ersetzen \
mit /
:
$ !!:gs/\\/\/
bash: :gs/\\/\/: substitution failed
Ich bin mir nicht sicher, warum die Substitution fehlgeschlagen ist.
Ich habe auch versucht:
$ !!:gs/\\/q
Nur um zu sehen, ob der Ersatz das Problem war. Es ist nicht. Jetzt bin ich neugierig!
Warum bekomme ich "Substitution fehlgeschlagen"?
cd 'C:\foo\bar'
!!:gs/\\/\/
funktioniert in zsh…fc -s '\'='/' -1
funktioniert unter der Ubuntu LTS-Standard-Bash. Lassen Sie mich wissen, ob es auch unter Cygwin funktioniert. Ich habe mehr Wörter in der Antwort gepostet.!!:gs/\\/\//
. @Hastur 'sfc -s '\'='/' -1
bekommt das erwartete Verhalten. Dies könnte ein Fehler in Bash sein.Antworten:
Ein Schrägstrich ist auch das Trennzeichen Ihres Ersatzbefehls. Sie müssen ihn daher als Ersatzzeichenfolge maskieren, um die Substitution nicht vorzeitig zu beenden
oder klarer, wie in den Kommentaren vorgeschlagen, indem Sie etwas anderes als einen Schrägstrich als Trennzeichen verwenden
Aber dies scheint nur zu funktionieren
tcsh
(die Shell, die normalerweise dort zugewiesen wird, wo ich bin). Ich kann den Befehl nicht zum Arbeiten bringen,bash
da es so aussieht, als würde das Entkommen beim ersten Argument von nicht funktionieren:s
quelle
!!:gs|\\|/
Vielleicht etwas lesbarer.:s
Argument von scheint kein echter Regex zu seinKurze Antwort: das eingebaute
fc
(Fix-Kommando) von Bashfc
ist der Befehl, built-in in der bash, vorgenommen Bearbeiten und Befehle der Geschichte erneut auszuführen.Es ist auch auf CygWin vorhanden und funktioniert auf allen Linux-Distributionen, auf denen ich getestet habe:
Einige Erklärungen
fc
ist der in bash integrierte Befehl zum Auflisten oder Bearbeiten und erneuten Ausführen von Befehlen aus der Verlaufsliste.-1
übernimmt den letzten Befehl in der Geschichte. Beachten Sie, dass sogar!!
als definiert (gelesen vonman bash
) ist-s
ein Muster durch ein anderes ersetzen. Diesmal abhelp fc
(eingebauter Befehl alsohelp
):Ok sie meinen
pat=rep
stattOLD=NEW
...'\'
und'/'
.Einige Worte mehr darüber, warum Sie "Substitution fehlgeschlagen" erhalten.
Es scheint, dass für den
s
Modifikator (noch) nicht die Ersetzung des Backslash-Zeichens implementiert ist\
, das ist das Escape- Zeichen . Um sicherzugehen, dass wir zum Beispiel den Code der gnu-Version der Bash-Verlaufserweiterung sehen sollten (aber es gab den obigen Befehl, um zu erhalten, was Sie versucht haben ... also nehme ich es faul ...).Einige Notizen:
Wir glauben, dass es bei jedem RegEx funktioniert, mit dem wir arbeiten
sed
, aber es ist nicht garantiert. Der Backslash ist der Escape-Charakter der Erweiterung und das Problem ist hier. Darüber hinaus hängt das Verhalten der Erweiterung mit denshopt
Optionen zusammen, sodass wir von Fall zu Fall sehen sollten ...Wenn Sie den String
cd C:\Foo\Bar
in Ihre Bash-Shell einfügen , wird er erweitert und für den Interpreter alscd C:FooBar
angezeigt. In dieser Form wird es auch in der$_
internen Variablen gespeichert .Wenn Sie stattdessen eingefügt
cd "C:\Foo\Bar"
odercd 'C:\Foo\Bar'
in die$_
Variable, sollten Sie findenC:\Foo\Bar
.Da die Verlaufserweiterung unmittelbar nach dem Lesen einer vollständigen Zeile ausgeführt wird, bevor die Shell sie in Wörter zerlegt, könnten Sie versucht sein, sie mit einem mehr oder weniger einfachen Bashismus zu verwenden , z. B. mit einer Ableitung von (möglicherweise Hinzufügen
:p
oder:q
,""
, Parsen und so weiter ...)Dies ist der Moment, um sich daran zu erinnern, dass es nicht sicher ist , mit Pfad und Dateinamen zu spielen , insbesondere wenn sie aus der Windows-Zwischenablage stammen (lesen Sie im Allgemeinen die Seite Warum nicht analysieren
ls
?, Es hängt im Wesentlichen mit der Möglichkeit zusammen, Tabulatoren zu verwenden). Leerzeichen und Zeilenumbrüche als korrekte Zeichen für die Dateinamen und die Verzeichnisnamen ...).Wenn Sie einen mit der Maus aufgenommenen Text einfügen , können Sie auch ein führendes Leerzeichen einfügen. Dadurch wird möglicherweise vermieden, dass Ihr Befehl im Verlauf beendet wird (dies hängt von den Shell-Optionen ab ...). Wenn ja, ist Ihre folgende
!!
Anweisung ein nicht kontrollierter Befehl ... (siehe ein Beispiel in einer anderen Antwort ).Dies ist ein nicht benötigtes materielles Risiko .Fazit
Wenn es nicht einfach ist, denke ich, dass wir etwas falsch machen
;-)
Ad nauseam: ein kleines Experiment
Ich habe dann
histverify
in der Shell aktiviert ...dann drücke ich Enterund als verifizierte Erweiterung finde ich
dann drücke ich Enternochmal und es hallt
Dies scheint darauf hinzudeuten , dass die
substitution failed
in der Geschichte Expansion vor der verarbeiteten erzeugt Expansion Brace , so vor allem , und es scheint zu bestätigen , dass dies
Geschichte Modifikator nicht (noch) die Substitution des Prozesses\
Charakter als echte regex. ..quelle
Sie können
sed
das Ergebnis ersetzen und ausführen.Es gibt mehrere mögliche Varianten für einen solchen Befehl, aber bei meiner Bash hat nur diese funktioniert:
Das
\\
wird hinzugefügt,!!
falls der letzte Befehl mit einem Backslash beendet wird. Ohne sie wird die Shell verwirrt und fragt nach der Fortsetzung der Linie.Sie können dies auch als Bash-Funktion in die Datei einfügen
~/.bashrc
:So funktioniert das auf meinem Bash unter Windows:
So erklären Sie, wie der
A=
Befehl der Shell-Variablen den richtigen Wert zuweistA
:tail
Nimmt die letzten beiden Zeilen aus dem Befehlsverlauf, der die Zeilen voncd \mnt\c
gefolgt von sichslash
selbst angibt. Der Teil vonhistory | tail -n 2
kann auch geschrieben werden alshistory 2
.head
Nehmen Sie die erste Zeilecd \mnt\c
cut
schneidet die von gelieferte Zeilennummer aushistory
sed
ersetzt alle Schrägstriche durch Schrägstricheeval
führt den Inhalt der Variablen ausA
quelle
A=$(echo "!!\\" | sed 's,\\,/,g');eval $A
tut mir leid zu sagen, dass dies auf meiner GNU-Bash-Version 4.3.11 (1) nicht funktioniert, wenn der Befehl mit einem Backslash beendet wurde. Sie sind gezwungen, ein Leerzeichen hinzuzufügen, z. B.C:\Foo\Bar\
, wie Sie sagten, wartet die Shell auf die Fortsetzung der Zeile. Sie können die Eingabetaste auch zweimal drücken. Im ersten Fall erhalten SieC:/Foo/Bar /
(mit einem Leerzeichen vor dem/
; im zweiten Fall wird ein Fehler generiert. Die Funktion funktioniertIch glaube nicht, dass du das kannst. Sie müssen erneut kopieren / einfügen.
Das Problem hängt nicht mit dem Schrägstrich zusammen, sondern auch mit dem Ersatzbefehlstrennzeichen, da der Ersatzbefehl jedes Trennzeichen akzeptiert. Es geht um die zu ersetzenden Schrägstriche, die bereits als einfache nutzlose Charakterhemmnisse auf der rechten Seite behandelt wurden.
Wenn Sie den Ersatzbefehl aufrufen, ist der Backslash bereits aus der Quelle verschwunden. Versuchen Sie einfach, den Befehl wie er ist (
!!
) erneut aufzurufen . Anstatt genau den gleichen Befehl einschließlich zu druckenc:\foo
, wird der Befehl abzüglich bereits verarbeiteter Backslashes ausgeführt, die dazu führenc:foo
.Und natürlich können Sie einen fehlenden Charakter nicht finden oder ersetzen. Wenn Sie dies versuchen, wird ein Fehler ausgelöst.
quelle
echo c:\Foo
gefolgt von!!:gs,F,\\f,
. Aber das Ersetzen der Backslash-Flucht selbst scheint ein Schmerz zu sein.