Was ist "-bash:!": Ereignis nicht gefunden "

114

Versuchen Sie, Folgendes unter einer Bash-Shell auszuführen echo "Reboot your instance!"

Auf meiner Installation:

root@domU-12-31-39-04-11-83:/usr/local/bin# bash --version
GNU bash, version 4.1.5(1)-release (i686-pc-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
root@domU-12-31-39-04-11-83:/usr/local/bin# uname -a
Linux domU-12-31-39-04-11-83 2.6.35-22-virtual #35-Ubuntu SMP Sat Oct 16 23:57:40 UTC 2010 i686 GNU/Linux
root@domU-12-31-39-04-11-83:/usr/local/bin# echo "Reboot your instance!"
-bash: !": event not found

Kann mir jemand bitte erklären, was "bash events" sind? Ich habe dieses Konzept noch nie gehört. Wie soll ich auch "!" am Ende des Satzes?

Maxim Veksler
quelle

Antworten:

53

Sie können die Protokollersetzung mit deaktivieren set +H.

Dennis Williamson
quelle
2
Kennen Sie die Gründe für die Syntax? Es scheint wirklich kontraintuitiv zu sein. Sie würden denken, Sie würden +Hetwas -Heingeben , um etwas zu aktivieren und zu deaktivieren.
Gavin Ward
7
@PunkyGuy: Ich kenne die Geschichte dahinter nicht (Wortspiel beabsichtigt), aber Unix-Optionen beginnen normalerweise mit einem Bindestrich (oder Minus) und +sind einfach das Gegenteil davon.
Dennis Williamson
105

!ist ein spezielles Zeichen, mit dem auf frühere Befehle verwiesen wird. z.B,

!rm

ruft den letzten Befehl auf, der mit der Zeichenfolge "rm" und "rm" begann, und führt ihn aus

!rm:p

ruft den letzten Befehl auf, der mit der Zeichenfolge "rm" begonnen hat, führt ihn jedoch nicht aus. bash interpretiert das Ausrufezeichen in echo "reboot your instance!"als „ Ersatz hier den letzten Befehl, der mit dem Buchstaben begann (s) unmittelbar nach dem Ausrufezeichen “, und schimpft auf Dich , dass es kein Ereignis (Befehl) in Ihrer Geschichte finden kann , die mit einem einzigen begannen doppelte Anführungszeichen.

Versuchen

echo reboot your instance\!

das Ausrufezeichen vor Bash schützen.

MadHatter
quelle
Ja, aber sollte passieren, wenn ich echo verwenden möchte -e "Etwas Text $ ENV_VAL Etwas mehr Text \ nJetzt neu starten!" ?
Maxim Veksler
1
Schreiben Sie zwei Echo-Anweisungen. Sie erhalten den Zeilenvorschub kostenlos.
MadHatter
1
Eine einfache Lösung besteht darin, einfache und doppelte Anführungszeichen gleichzeitig zu verwenden: echo -e "Text \ nReeboot" '!'
2.
4
Das ist scheiße. Wenn ich dem Ausrufezeichen nicht entkomme, löst Bash einen Anfall aus. Wenn ich es nicht tue , ist der Backslash in der letzten Zeichenfolge enthalten. Warum tust du das, Bash !! ( pastebin.com/g4PYv56A )
Hubro
2
@Hubro Fairerweise bin ich mir nicht sicher, ob das alles Bashs Schuld ist. Sie haben etwas komplizierte Probleme, wenn Sie Ruby verwenden, um die Bash zu füttern, und mir ist nicht klar, welche Rolle Ruby beim Abstreifen oder Verstärken von Fluchtcharakteren spielt.
MadHatter
25

Verwenden Sie einfache Anführungszeichen anstelle von doppelten Anführungszeichen, um Ihr ursprüngliches Problem zu lösen. Bei letzterem versucht bash, bestimmte Zeichen zu erweitern, bevor das Ergebnis an den Befehl übergeben wird (in diesem Fall Echo). Mit einfachen Anführungszeichen übergibt bash die gesamte Zeichenfolge unverändert.

!wird in Befehlen verwendet, um auf den Befehlszeilenverlauf zu verweisen. Siehe: http://tldp.org/LDP/abs/html/abs-guide.html#HISTCOMMANDS für einen vollständigen Satz. Im obigen Beispiel versucht bash, !"als Referenz auf ein Ereignis zu expandieren, bevor das Echo einen Einblick erhält, daher der Fehler.

Beachten Sie, dass in Skripten alle Verlaufsbefehle deaktiviert sind, da sie nur in einer interaktiven Shell sinnvoll sind.

Das einzige, das ich regelmäßig benutze, ist !$. Es wird bis zum letzten Argument des vorherigen Befehls erweitert. Es ist eine nützliche Abkürzung.

SmallClanger
quelle
4
!!Es ist bemerkenswert nützlich, den zuletzt eingegebenen Befehl vollständig auszufüllen. insbesondere sudo !!oderpfexec !!
jgoldschrafe
2
Ich finde auch, dass sudo und pfexec nette Dienstprogramme sind, aber ich muss nicht so begeistert sein.
LeartS
$_funktioniert in mehr Shells als Bash und ist im Gegensatz dazu eine richtige Variable !$. (und @LeartS: Ich mochte den Mangel an Emoticons deines Witzes.;))
ΤΖΩΤΖΙΟΥ
7

Setzen Sie einfach ein Leerzeichen dazwischen! und "dann klappt es.

Prost.

Isik Mater
quelle
2
Könnten Sie bitte eine Erklärung hinzufügen, warum Ihre Lösung funktioniert?
200_success
2
Dies funktioniert, weil Bash nur behandelt! als Sonderzeichen, wenn es direkt von einem Nicht-Leerzeichen gefolgt wird. Es wird jedoch auch ein zusätzliches Leerzeichen zu Ihrer Ausgabe
hinzugefügt
2

Ja, ! ist ein Sonderzeichen, mit dem auf frühere Befehle verwiesen wird.

Nur wenige Möglichkeiten, mit der Situation umzugehen

Das Folgende gibt die Zeichenfolge so aus, wie sie ist

echo 'Reboot your instance!'

Der folgende Befehl führt den Befehl aus und verkettet die Zeichenfolge

echo 'escaping #'" adding `which python` to the string"
echo '#!'`which python`
Syed Qaiser
quelle
1

In bash 4.3scheint es brauchen Sie nicht mehr einfache Anführungszeichen zu verwenden , oder set +H:

$ bash --version
GNU bash, version 4.3.46(1)-release (x86_64-unknown-linux-gnu)
[...]
$ echo "Reboot your instance!"
Reboot your instance!
Eugene Yarmash
quelle
Wahrscheinlich ein Bug, denn hier habe ich 4.4.12 und nochmal brauche ich set +Hoder zitiere. Oder Sie haben set +Hirgendwo (wie in /etc/profile).
Bodo Thiesen
Wenn Sie! -Char nicht am Ende des Satzes verwenden, wird überprüft, ob die Ereigniserkennung von bash noch einwandfrei funktioniert. Version ist 4.3.30 ........ $ echo "Überprüfen Sie Ihren Satz! Foo" bash
:!
0

Du könntest auch einen Heredoc benutzen :

cat <<EOF
Reboot your instance!
EOF

Es ist in diesem Fall ärgerlich, weil es kein Einzeiler ist, aber für längere Befehle (wie das Schreiben eines Bash-Skripts) funktioniert es großartig.

Tom Saleeba
quelle