Не можете використовувати знак оклику (!) В bash?


86

Я намагаюся використовувати команду curl для доступу до URL-адреси http зі знаком оклику ( !) на своєму шляху. наприклад:

curl -v "http://example.org/!287s87asdjh2/somepath/someresource"

відповідь консолі с bash: ... event not found.

Що тут відбувається? і який би був правильний синтаксис для уникнення знака оклику?


Вирішений в базі 4.4+
Ісаак

Відповіді:


98

Знак оклику є частиною розширення історії в баші. Щоб використовувати його, вам потрібно укласти його в окремі лапки (наприклад:) 'http://example.org/!132'або безпосередньо вийти з його косою рисою ( \) перед символом (наприклад:) "http://example.org/\!132".

Зауважте, що у подвійних лапках зворотна косої риски перед вигуком запобігає розширенню історії, Але НЕ зворотній косої риси не знімається в такому випадку. Тому краще використовувати одинарні лапки, щоб ви не передавали буквальний зворотний косий рядок curlяк частину URL-адреси.


8
"http://example.org/\!132"насправді розширюється без інтерпретації зворотної косої риси (я вважаю, що відповідність POSIX).
Кріс Даун

@ChrisDown, я намагався уточнити, що це мій другий варіант у тексті. Дякуємо, що вказали на потенційність плутанини.
Даніель Піттман

6
Для запису: спробувати втечу "!" Не переносимо. Рекомендація щодо передового досвіду - завжди цитувати (синг-котирування) "!". Пов’язане: "^" (caret) - це неметахарактер, який потребує цитування для портативності. Нарешті, "!" не слід використовувати в операторі if; використовуйте його як аргумент для тестування замість цього, якщо можливо (знову ж таки через Solaris / bin / sh).
Ніколас Вілсон

5
Для мене працювали лише окремі цитати. zsh досі інтерпретував \!і подвійні цитати.
orkoden

1
У програмі Solaris (сміття, стара оболонка до XPG4) '^' - псевдонім для |і використовується для створення труби. Якщо ви надсилаєте сценарії клієнтам і не можете бути впевнені, у якій оболонці вони запускатимуться, вам доведеться протестувати з ними всі!
Ніколас Вілсон

61

Як і відповідь Даніеля, ви також можете просто вимкнути розширення історії, якщо ви цим не користуєтесь set +H.


19
Всього вимкнення розширення історії - найкраща порада, яку я чув протягом усього дня! Розширення історії є небезпечним і візантійським, коли є набагато кращі альтернативи (покроковий пошук історії Ctrl-R), які дозволяють вам переглядати та редагувати свою команду, щоб ви не сліпо вистрілили команду, !-14яка вам хоч і була !-12, ой, трапилось rm -rf *. Будь обережним. Вимкнути розширення історії! Уникнути !!
aculich

6
Найбільша відповідь: розширення історії - це величезний ризик для безпеки! Він може використовуватися для атаки на ваш Unix через створену URL-адресу.
дан

@aculich або просто скористайтеся вказаною командою POSIX fc -14. Але це правда, що ви можете це зробити і без включення розширення історії. Особисто я використовую !$і, !viі sudo !!навіть git add !vi:$досить часто, вимагаю ввімкнення розширення історії.
Wildcard

Я думаю, я додам це до своїх RC-файлів оболонки. Я лише коли-небудь використовував це як акуратний "трюк"
TonyH

17

Я б особисто робив одинарні лапки, але для повноти також зазначу, оскільки це URL-адреса, ви можете кодувати !як %21, наприклад curl -v http://example.org/%21132.


13

Це також може зробити

curl -v "http://example.org/"'!'"287s87asdjh2/somepath/someresource"
або
curl -v "http://example.org/"\!"287s87asdjh2/somepath/someresource"

Що працює, тому що bash об'єднує суміжні струни. Цей підхід особливо корисний, коли у вас є інші речі, для яких потрібне розширення оболонки, тому ви не можете використовувати одинарні лапки для всієї рядка:

curl -v 'http://example.org/!'"287s87asdjh2/${basepath}/someresource"

!символ використовується для розширення історії в командному рядку.
тож це може бути проблемою у швидкому, але не у файлах скриптів оболонки.
як ви бачите, розширення історії працюють навіть у подвійних лапках.


Існує безліч способів змусити команди Unix та англійські речення використовувати більше символів, ніж потрібно, і бути більш заплутаним, ніж потрібно. Наскільки це перевершує першу / прийняту / найвищого голосування відповідь, а саме, розміщуючи всю URL-адресу в єдині лапки?
G-Man

2
@ G-Man: Це інший спосіб побудувати аргументи bash. Я не знав про цей метод. Нічого поганого в навчанні нових речей.
Сахіл Сінгх

@SahilSingh Як це нове? Він об'єднує три рядки, дві укладені в подвійні лапки і одна, що вкладається в одинарні лапки. Тут немає гніздування.
Рафаель

@ G-Man Не очевидно, що коли ви ставите 2 рядки один біля одного, вони об'єднуються. printf ("привіт" "світ") також буде працювати в c, але printf ("привіт" 'w') не буде працювати, тому ви бачите, що знання, що баш вміщує такі вирази, було для мене новим, але я згоден з точки зору корисності, це не є вищим. Відповідь мені сподобалась, так само зробив і Марк Шуст.
Сахіл Сінгх

2
@ G-Man Це також корисно, коли є інші розширення рядків , які хочуть відбуватися в одній і тій же строці. Це простий спосіб розділення двох типів поведінки цитування.
WAF

7

Я зіткнувся з тією ж проблемою, і моїм простим рішенням було використання змінної:

E=!  
curl -v "http://example.org/${E}287s87asdjh2/somepath/someresource"

Тут простота полягає в тому, що (1) Він портативний через оболонки та команди (2) Не вимагає знання синтаксису втечі та кодів ASCII.


3

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

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

це не працює за межами echo, ехо, здається, справляється з цим по-різному самостійно
phil294

@Blauhirn Це не має нічого спільного з відлунням, і все, що стосується цитування та версії bash, яку ви запускаєте.
Flimm

2
Ця відповідь невірна і її слід видалити. Ваша bashверсія не має нічого спільного з тим, щоб чубок не розширювався, це пов'язано з тим, що у вашому прикладі !після цього йде "кінець рядка" і це заважає оболонці намагатися розширити її. Спробуйте, echo "!Hello World"і ви побачите, що bashвідповість с bash: !Hello: event not found. Детальнішу інформацію див. У посібнику
don_crissti

0

Для тих, хто використовує git bash у windows, прийнята відповідь від @DanielPittman працює. Однак слід змінити нахил косої риски (\) на пряму косу рису (/).

Наприклад, в unix це виглядатиме приблизно так:

curl https://abc.com/services -H 'Authorization: Bearer 111A80BBZZCnS\!ZR412543s'

Для Windows це буде щось подібне (зосередьтеся на переднім косому напрямку в частині заголовка авторизації)

curl https://abc.com/services -H 'Authorization: Bearer 111A80BBZZCnS/!ZR412543s'


Це не має особливого сенсу. У вас аргументований єдиний аргумент, тому незалежно від косої риски вигук не призведе до розширення історії.
Wildcard

Ой ти маєш рацію. Цю відповідь я опублікував лише тому, що коли я використовував відповідь Даніеля (за допомогою зворотної косої риси), з’являється помилка.
СамуельДев
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.