Як відлуння чуб!


59

Я спробував створити сценарій, echoвнісши вміст у файл, а не відкривати його редактором

echo -e "#!/bin/bash \n /usr/bin/command args"  > .scripts/command

вихід :

bash:! / bin / bash: подія не знайдена

Я виділив цю дивну поведінку на чубку .

$ echo !
!  

$ echo "!"
bash: !: event not found

$ echo \#!
#!

$ echo \#!/bin/bash
bash: !/bin/bash: event not found
  • Чому чубство викликає це?
  • Які ці "події", на які посилається Баш?
  • Як мені подолати цю проблему та надрукувати "#! / Bin / bash" на екран чи мій файл?

Відповіді:


59

Спробуйте використовувати окремі цитати.

echo -e '#!/bin/bash \n /usr/bin/command args'  > .scripts/command

echo '#!'

echo '#!/bin/bash'

Проблема виникає через те, що bash шукає свою історію для! / Bin / bash. Використання одинарних лапок уникає такої поведінки.


3
Він також вимикає
рядкову

В тім-то й річ! Ви можете додати інші аргументи до тієї самої команди ехо, використовуючи подвійні лапки і отримати інтерполяцію в цих частинах.
Річм

3
ви також можете використовувати рядок у стилі C в bash з $''. Наприклад, echo $'1!\n2!\n3!\n'друкується кожне число з подальшим чубком та новим рядком.
spelufo

1
Введення чуб в одинарні лапки не допомогло мені при введенні багаторядкового рядка:! bash - одиничні цитати не втечуть від удару (справжнього)
binki

1
@kbolino Ви маєте рацію. Таким чином, повний приклад рядка був би: echo '0123'"$var"'456'відзначте дві пари одиничних лапок і одну пару подвійних лапок.
фіат

16

Як сказав Річм , Баш намагається провести матч історії . Ще один спосіб уникнути цього - просто уникнути чуба \:

$ echo \#\!/bin/bash
#!/bin/bash

Хоча будьте обережні, що всередині подвійних лапок цей параметр \не видаляється:

$ echo "\!"
\!

8
В bash, "\!"насправді розширюється до \!, ні !, нібито для відповідності POSIX.
Мікель

@Mikel Зітхання. Стільки різниць між zsh та bash
Michael Mrozek

Це працює навіть під час введення багаторядкового рядка. Пам'ятаючи про те, що під час вступу на чуб 1. бути поза рядком і 2. використовувати цей метод (зворотний косий рядок), як видається, працює у найменшому сюрпризі у більшості сценаріїв.
бінкі

1
Було б корисно відзначити, що bash не виконує пошук історії під час виконання сценарію, тому не потрібно робити там нічого особливого.
бінкі

Чи не існує синтаксису, щоб просто уникнути !подвійних лапок без магічної поведінки? Це горіхи ...
Лассі

13

!починає заміну історії ("подія" - рядок в історії команд); наприклад, !lsрозширюється на останній командний рядок, що містить ls, і !?fooрозширюється на останній командний рядок, що містить foo. Ви також можете витягти конкретні слова (наприклад, !!:1посилається на перше слово попередньої команди) та інше; Детальну інформацію див. у посібнику.

Ця функція була придумана для швидкого згадування попередніх команд у дні, коли видання командного рядка було примітивним. З сучасними оболонками (принаймні, bash та zsh) та копіюванням та вставкою розширення історії не настільки корисне, як раніше - все-таки корисно, але ви можете обійтися без цього.

Ви можете змінити, який символ запускає заміну історії, встановивши histcharsзмінну; якщо ви рідко використовуєте підстановку історії, ви можете встановити, наприклад, histchars='¡^'таким чином, щоб ¡замість цього було запущено розширення історії !. Ви навіть можете повністю вимкнути функцію set +o histexpand.


3

Щоб вимкнути розширення історії в певному командному рядку, ви можете використовувати spaceяк 3-й символ $histchars:

histchars='!^ '

Тоді, якщо ви введете свою команду з провідним простором, розширення історії не буде виконуватися.

bash-4.3$ echo "#!/bin/bash"
bash: !/bin/bash: event not found
bash-4.3$  echo "#!/bin/bash"
#!/bin/bash

Однак зауважте, що провідні пробіли також використовуються, коли $HISTCONTROLмістять ignorespaceяк спосіб сказати bashне записувати командний рядок в історію.

Якщо ви хочете, щоб обидві функції були незалежно, вам потрібно вибрати інший символ як 3-й символ $histchars. Ви хочете, щоб він не впливав на інтерпретацію вашої команди. Кілька варіантів:

  • використання зворотної косої риски ( \): \echo fooпрацює, але це побічний ефект відключення псевдонімів або ключових слів.
  • ТАБЛИЦЯ: щоб вставити її в перше положення, потрібно натиснути, Ctrl+VTabхоча.
  • якщо ви не заперечуєте , набравши два ключа, ви можете вибрати будь-який символ , який зазвичай не з'являється в першій позиції ( %, @, ?, вибрати свій власний) і залишається порожнім псевдонім для нього:

    histchars='!^%'
    alias %=

    Потім введіть цей символ, пробіл і вашу команду:

    bash-4.3$ % echo !!
    !!

(Ви не зможете не записати команду , де історія заміна була відключена , хоча. Також зверніть увагу , що за замовчуванням третій характером $histcharsє #таким , що розширення історії не робиться в коментарях. Якщо ви зміните його, і ви вводите коментарі на підкажіть, вам слід знати про те, що послідовності !, там можуть бути розширені).


2

Запропоновані рішення не працюють, наприклад, у наступному прикладі:

$ bash -c "echo 'hello World!'"
-bash: !'": event not found
$

У цьому випадку чубок можна роздрукувати за допомогою восьмеричного коду ASCII:

$ bash -c "echo -e 'hello World\0041'"
hello World!
$

1
У вашій першій команді значення !знаходиться між подвійними цитатами, де, як свідчать інші відповіді, воно зберігає значення розширення історії. Ви можете використовувати bash -c 'echo '\''hello World!'\'або bash -c "echo 'hello World"\!"'".
Жиль

Без параметра -i середовище може бути змінено (наприклад, ваш ~ / .profile не працює). Однак виконання -i означає, що будь-який вихід з вашого .profile буде зафіксований у висновку команди, яку ви насправді хочете виконати.
Брент

-1

Починаючи з Bash 4.3, тепер ви можете використовувати подвійні лапки, щоб процитувати характер розширення історії:

$ bash --version
GNU bash, version 4.3...
[...]
$ echo "Hello World!"
Hello World!

4
Ні, це лише !слідом за "цим вже не є особливим. echo "foo!"все гаразд, echo "foo!bar"ні
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.