Jak mam uciec od wykrzyknika?

183

Chcę zrobić coś takiego bzr commit -m "It works!". Mogę w ten sposób uciec od wykrzyknika bzr commit -m "It works\!". Jednak mój komunikat zatwierdzenia zawiera odwrotny ukośnik. Jak uciec od wykrzyknika, jednocześnie ignorując ukośnik?

Mateusz
źródło
1
Robi też bzr commit -m "It works"!prace.
kba
1
Jak zauważyłem przed wprowadzeniem polecenia, działa ono właściwie :)bzr commit -m "It works!"
h4unt3r
Jeszcze dziwniejsza sprawa z zagnieżdżonymi cytatami: stackoverflow.com/questions/22125658/...
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
1
Chociaż zaakceptowana odpowiedź jest dobrym rozwiązaniem dla twoich problemów z zatwierdzaniem, wydaje mi się, że nie jest to odpowiedź na rzeczywisty problem: rozszerzenie historii Bash . Proszę rozważyć zaakceptowanie odpowiedzi Dennisa?
Arjan

Odpowiedzi:

153

Ponieważ nie jesteś zależny od bash do rozwijania zmiennych w komunikacie zatwierdzenia, możesz zamiast tego użyć pojedynczych cudzysłowów. Ciągi w pojedynczych cudzysłowach nie są rozwijane przez bash.

bzr commit -m 'This does work!' 
Benjamin Bannier
źródło
24
Ponieważ pytanie brzmiało: „Jak uciec od wykrzyknika?” a nie „Jak nie rozwinąć wykrzyknika?” Nie sądzę, żeby to było ważne. Są chwile (jak na przykład przekazywanie apostrofów i wykrzykników w tym samym wierszu poleceń), że to nie działa. Poniższa odpowiedź działa znacznie lepiej, aby zrobić to, czego potrzebuje wiele osób.
Jann
7
@Jann: Masz 100% rację, ale myślę, że tutaj jest problem z tyloma pytaniami na temat superużytkownika: czy odpowiadamy na to pytanie, czy pomagamy ludziom rozwiązać ich konkretny problem. Myślę, że oba sposoby mogą być przydatne i szukałem pomocy w konkretnej sprawie.
Benjamin Bannier
touché! To był konkretny problem. Po prostu chcę, aby odpowiedź na moje pytania mogła być wykorzystana w wielu sytuacjach. PS: Powodem, dla którego wspomniałem o tym, było to, że musiałem przekazać zarówno apostrof, jak i wykrzyknik programowi perl, i potrzebowałem poniższego rozwiązania. :)
Jann
Zgadzam się zarówno z Benjaminem, jak i Janem, ale głosowałem negatywnie. Tytuł pytania jest indeksowany przez wyszukiwarki i tak tu przyszedłem i prawdopodobnie przybywa tu większość użytkowników. Dlatego uważam, że ważne jest, aby pytanie odzwierciedlało rzeczywiste pytanie. Na innych forach ludzie powinni (prawie zmuszeni) zapytać dokładnie, czego szukają. Odpowiadanie na źle sformułowane pytania przemawia za niechlujstwem i to jest właśnie powód mojej opinii poniżej. Jako kompromis / rozwiązanie proponuję pomóc w dostosowaniu nagłówka, aby odzwierciedlał rzeczywisty problem.
ChristophK,
153

Oto kolejna metoda, jeśli chcesz podwójne cudzysłowy, a także wykrzyknik:

echo "It's broken"'!'

Działa to nawet wtedy, gdy !nie ma go na końcu linii.

Na przykład:

echo "hello there"'!'" and goodbye"

Premia: Podobną technikę można zastosować, aby uciec przed dowolnym tekstem w Sh lub Bash (za pomocą sed): patrz pierwsza opcja w tej odpowiedzi . Ponadto, jeśli masz bash-completionzainstalowany, może mieć funkcja już dostępne.quote()

jwd
źródło
4
Dobra wskazówka, JWD. Nie zdawałem sobie sprawy, że łańcuchy bash można połączyć, po prostu pomijając między nimi białe spacje.
Alan H.
Właściwie, jeśli wykrzyknik znajduje się na końcu łańcucha, to w wyraźnej postaci echo "Happy birthday!"będzie działał zgodnie z oczekiwaniami, w przeciwnym razie możesz uciec z ukośnikiem odwrotnym, ale wydrukowany zostanie również ukośnik odwrotny XD Bash nie jest dla osób o słabym sercu :)
h4unt3r
@ h4unt3r: Dziwne, to nie jest moje doświadczenie. Dla mnie echo "Happy Birthday!"wyprowadza 2 linie. Pierwszy to echo "Happy birthday"(bez wykrzyknika), a drugi to „Wszystkiego najlepszego” (znowu bez wykrzyknika). Czy masz włączone rozszerzanie historii podczas wykonywania tego testu?
jwd
@jwd jaką wersję bash używasz? Zawsze mam włączone rozszerzenie. Czy przypadkowo użyłeś dwóch !! na twój test?
h4unt3r
@ h4unt3r: version 4.1.2(1)-release (x86_64-redhat-linux-gnu)zdecydowanie !używany jest tylko jeden . Mam udział histexpandw $SHELLOPTS. Jednak właśnie wypróbowałem wersję 4.3.18 (2) na innym komputerze i działa ona tak, jak opisano. Chyba naprawiono błąd.
jwd
66

Wyłącz rozszerzanie historii :

set +H

lub

set +o histexpand

Możesz dodać jedno z tych poleceń, ~/.bashrcjeśli zwykle nie używasz rozszerzania historii.

Bash 4.3 dodał specjalny przypadek :

znak rozwinięcia historii jest również traktowany jako cytowany, jeśli bezpośrednio poprzedza podwójny cudzysłów zamykający w ciągu podwójnego cudzysłowu

Dennis Williamson
źródło
Dzięki - to działało, ale musiałem to zrobić set +o histexpand, nie set -o histexpand. Czy możesz edytować swoją odpowiedź, aby to naprawić?
Matthew
Ups, literówka, przepraszam. Naprawiony.
Dennis Williamson
znakomity! szukał tego dla WIEKÓW .... dzięki vm! jak ucieczka nie zadziała ... Nie chcę też używać pojedynczych cudzysłowów ... Dodam to do mojego .bashrcthx !!, nigdy nie używane !w skryptach i na darmo !! zawsze było kłopotliwe ...
Aquarius Power
To jest niesamowite! echo "@AquariusPower!"
joehanna
12

Używaj pojedynczych cudzysłowów (') zamiast podwójnych cudzysłowów ("). Pojedyncze cudzysłowy wyłączają wszelką interpretację zawartych w nich treści, podczas gdy podwójne cudzysłowy wyłączają tylko niektóre.

bzr commit -m 'It works!'
KeithB
źródło
4

Właśnie znalazłem inny sposób, który będzie działał przynajmniej z echociągami (zdaniami), które chcesz interpunkować wykrzyknikiem. Robi to mniej więcej końcowy etap wokół rozszerzenia Bash i kodowanie zajmuje tylko trochę więcej czasu.

Heks wykrzyknika, wymieniony na stronie http://www.ascii-code.com/ , wynosi 21, więc jeśli umieścisz \x21na końcu łańcucha echo -e $foo, zrób $foowłasne rozwinięte echo [tzn. foo=$(echo -e "$foo")] zdobędziesz, gdy echo $fooznowu będzie ciąg z !na końcu. I nie ma też przełączania histexpand.

Na pewno działa w Bash 4+. Wcześniejsze wersje, ymmv.

SilversleevesX
źródło
Hmmm to dla mnie nie działa.
lzap
Nie rozumiem, co mówisz o echu. „echo -e” i „printf” interpretują kody ósemkowe, szesnastkowe i Unicode. W przypadku, gdy używasz któregokolwiek z nich, możesz użyć „\ 041” (ósemka dla „!”) Lub „\ x21” (hex), aby zastąpić wykrzyknik. Na przykład: printf "OMG\041". Jeśli budujesz ciąg cudzysłowu w miejscu innym niż echo lub printf, tak jak zapytał OP o łańcuch zatwierdzenia, możesz osadzić go $(echo -e "\041")w miejscu, w którym powinien znajdować się wykrzyknik. Tak: bzr commit -m "This is a great commit$(echo -e "\041")".
Todd Walton