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


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.