Co to jest „-bash:!”: Nie znaleziono zdarzenia ”

114

Spróbuj wykonać następujące czynności pod powłoką bash echo "Reboot your instance!"

W mojej instalacji:

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

Czy ktoś może wyjaśnić, co to są „imprezy bashowe”? Nigdy wcześniej nie słyszałem o tej koncepcji. Jak mam wypisać „!” na końcu zdania?

Maxim Veksler
źródło

Odpowiedzi:

53

Możesz wyłączyć podstawianie historii za pomocą set +H.

Dennis Williamson
źródło
2
Czy znasz uzasadnienie składni? Wydaje się to naprawdę sprzeczne z intuicją. Można by pomyśleć, że wpiszesz, +Haby włączyć lub -Hwyłączyć coś.
Gavin Ward
7
@PunkyGuy: Nie znam historii (zamierzonej gry słów), ale opcje Uniksa zazwyczaj zaczynają się od łącznika (lub minus) i +jest po prostu odwrotnością.
Dennis Williamson
105

!jest znakiem specjalnym do bash, służy do odwoływania się do poprzednich poleceń; na przykład,

!rm

przywoła i wykona ostatnie polecenie, które rozpoczęło się od łańcucha „rm”, oraz

!rm:p

przywoła, ale nie wykona ostatniego polecenia, które rozpoczęło się od łańcucha „rm”. bash interpretuje wykrzyknik echo "reboot your instance!"jako „ zastąp tutaj ostatnie polecenie, które zaczyna się od znaku (ów) bezpośrednio po wykrzykniku ”, i narzeka, że ​​nie może znaleźć zdarzenia (polecenia) w twojej historii, które zaczęło się od jednego cudzysłów.

Próbować

echo reboot your instance\!

w celu ochrony (ucieczki) wykrzyknika przed uderzeniem.

Szalony Kapelusznik
źródło
Tak, ale powinno się zdarzyć, jeśli chcę użyć echa -e „trochę tekstu $ ENV_VAL trochę więcej tekstu \ nRootuj teraz!” ?
Maxim Veksler,
1
Napisz dwie instrukcje echa; otrzymujesz linefeed za darmo.
MadHatter,
1
Prostym rozwiązaniem jest użycie pojedynczych cudzysłowów i podwójnych cudzysłowów jednocześnie: echo -e „Text \ nReeboot” '!'
mmey,
4
To jest do bani. Jeśli nie uniknę wykrzyknika, bash przyprawi mnie o atak. Jeśli to zrobię , odwrotny ukośnik jest zawarty w ostatnim ciągu. Dlaczego to robisz, Bash !! ( pastebin.com/g4PYv56A )
Hubro
2
@Hubro w uczciwości, nie jestem pewien, czy to wszystko wina basha. Masz nieco skomplikowane sprawy, używając ruby ​​do karmienia rzeczy do bashu, i nie jest dla mnie jasne, jaką rolę odgrywa ruby ​​w usuwaniu lub wzmacnianiu postaci ucieczki.
MadHatter
25

Aby rozwiązać pierwotny problem, spróbuj użyć pojedynczych cudzysłowów zamiast podwójnych. W tym drugim przypadku bash podejmie próbę rozwinięcia niektórych znaków przed przekazaniem wyniku do polecenia (w tym przypadku wykonaj echo). W przypadku pojedynczych cudzysłowów bash przekazuje cały ciąg znaków bez zmian.

!jest używany w poleceniach w celu odniesienia do historii wiersza poleceń. Zobacz: http://tldp.org/LDP/abs/html/abs-guide.html#HISTCOMMANDS dla pełnego zestawu. W powyższym przykładzie bash próbuje rozwinąć się !"jako odwołanie do zdarzenia, zanim echo się zajmie, stąd błąd.

Zauważ, że w skryptach wszystkie polecenia historii są wyłączone, ponieważ mają one sens tylko w interaktywnej powłoce.

Jedynym, z którego regularnie korzystam, jest !$. Rozwija się do ostatniego argumentu poprzedniego polecenia. W niektórych miejscach jest to przydatny skrót.

SmallClanger
źródło
4
!!wypełnienie ostatniego wpisanego polecenia jest niezwykle przydatne; w szczególności, sudo !!lubpfexec !!
jgoldschrafe
2
Uważam też, że sudo i pfexec to dobre narzędzia, ale nie muszę być tak entuzjastyczny.
LeartS
$_pracuje w więcej niż powłoki bash i jest to właściwa zmienna, w przeciwieństwie !$. (i @LeartS: Podobał mi się brak emotikonów twojego dowcipu;))
ΤΖΩΤΖΙΟΥ
7

Po prostu wstaw odstęp! i „niż to zadziała.

Twoje zdrowie.

Isik Mater
źródło
2
Czy możesz dodać wyjaśnienie, dlaczego Twoje rozwiązanie działa?
200_success
2
Działa to, ponieważ Bash tylko traktuje! jako znak specjalny, jeśli bezpośrednio po nim następuje znak spacji. Jednak doda również dodatkowe puste miejsce do twoich wyników, więc może nie zawsze być pożądane ...
mmey
2

Tak, ! jest znakiem specjalnym do bash, służy do odwoływania się do poprzednich poleceń.

Kilka sposobów poradzenia sobie z sytuacją

Poniższy kod wyświetli taki, jaki jest

echo 'Reboot your instance!'

Następujące polecenie wykona polecenie i połączy łańcuch

echo 'escaping #'" adding `which python` to the string"
echo '#!'`which python`
Syed Qaiser
źródło
1

W bash 4.3wydaje się nie trzeba już używać apostrofów lub 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
źródło
Prawdopodobnie błąd, ponieważ tutaj mam 4.4.12 i jeszcze raz muszę set +Hlub cytować. Lub masz set +Hgdzieś (jak w /etc/profile).
Bodo Thiesen
Użycie! -Char na końcu zdania sprawdza, czy wykrywanie zdarzeń bash nadal działa poprawnie. Wersja jest 4.3.30 ........ $ echo "Ponownie sprawdź zdanie! Foo" bash
:!
0

Możesz także użyć heredoc :

cat <<EOF
Reboot your instance!
EOF

W tym przypadku jest to denerwujące, ponieważ nie jest to jedna linijka, ale w przypadku dłuższych poleceń (takich jak pisanie skryptu bash), działa świetnie.

Tom Saleeba
źródło