Không thể sử dụng dấu chấm than (!) Trong bash?


87

Tôi đang cố gắng sử dụng lệnh curl để truy cập url http có dấu chấm than ( !) trong đường dẫn của nó. ví dụ:

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

giao diện điều khiển trả lời với bash: ... event not found.

Chuyện gì đang xảy ra ở đây? và cú pháp thích hợp để thoát dấu chấm than là gì?


Đã giải quyết trong bash 4.4+
Isaac

Câu trả lời:


99

Dấu chấm than là một phần của việc mở rộng lịch sử trong bash. Để sử dụng nó, bạn cần đặt nó trong dấu ngoặc đơn (ví dụ 'http://example.org/!132':) hoặc để trực tiếp thoát nó bằng dấu gạch chéo ngược ( \) trước ký tự (ví dụ "http://example.org/\!132":).

Lưu ý rằng trong dấu ngoặc kép, dấu gạch chéo ngược trước exclam ngăn chặn mở rộng lịch sử, NHƯNG dấu gạch chéo ngược không bị xóa trong trường hợp đó. Vì vậy, tốt hơn là sử dụng các trích dẫn đơn, để bạn không chuyển một dấu gạch chéo ngược theo nghĩa đen curlthành một phần của URL.


8
"http://example.org/\!132"thực sự mở rộng mà không diễn giải dấu gạch chéo ngược (lý do tuân thủ POSIX, tôi tin).
Chris Down

@ChrisDown, tôi đã cố gắng làm rõ đó là lựa chọn thứ hai của tôi trong văn bản. Cảm ơn đã chỉ ra tiềm năng cho sự nhầm lẫn.
Daniel Pittman

6
Đối với bản ghi: Nó không khả dụng để thử thoát "!". Đề xuất thực hành tốt nhất là luôn luôn trích dẫn (singe-trích dẫn) "!". Liên quan: "^" (dấu mũ), là một loại vi khuẩn không phải là metacharacter cần trích dẫn cho tính di động. Cuối cùng, "!" không nên được sử dụng trong một câu lệnh if; sử dụng nó làm đối số để kiểm tra thay thế nếu có thể (một lần nữa vì Solaris / bin / sh).
Nicholas Wilson

5
Chỉ trích dẫn duy nhất làm việc cho tôi. zsh vẫn đang giải thích \!và báo giá kép.
orkoden

1
Trên Solaris (vỏ cũ tiền XPG4), '^' là bí danh |và được sử dụng để tạo đường ống. Nếu bạn đang gửi tập lệnh cho khách hàng và không thể chắc chắn họ sẽ chạy tập lệnh nào, bạn phải kiểm tra tất cả!
Nicholas Wilson

61

Cũng như câu trả lời được đưa ra bởi Daniel, bạn cũng có thể tắt hoàn toàn lịch sử mở rộng nếu bạn không sử dụng nó với set +H.


19
Tắt hoàn toàn lịch sử mở rộng là lời khuyên tốt nhất tôi đã nghe cả ngày! Mở rộng lịch sử là nguy hiểm và byzantine khi có nhiều lựa chọn thay thế tốt hơn (tìm kiếm lịch sử gia tăng với Ctrl-R) cho phép bạn xem trước và chỉnh sửa lệnh của mình để bạn không bị bắn một cách mù quáng với lệnh !-14mà bạn đã !-12nghĩ rằng đó là điều rất đáng tiếc rm -rf *. Hãy an toàn. Vô hiệu hóa mở rộng lịch sử! Eschew !!
aculich

6
Câu trả lời lớn nhất: mở rộng lịch sử là một rủi ro bảo mật rất lớn! Nó có thể được sử dụng để tấn công Unix của bạn thông qua một URL được tạo.
dan

@aculich hoặc chỉ sử dụng lệnh do POSIX chỉ định fc -14thay thế. Nhưng đúng là bạn có thể làm điều đó mà không cần mở rộng lịch sử. Cá nhân, tôi sử dụng !$!visudo !!thậm chí git add !vi:$thường xuyên đủ để đảm bảo cho phép mở rộng lịch sử.
tự đại diện

Tôi nghĩ rằng tôi sẽ thêm nó vào tập tin RC shell của tôi. Tôi chỉ từng sử dụng nó như một "mánh khóe" gọn gàng
TonyH

17

Cá nhân tôi sẽ thực hiện các trích dẫn đơn lẻ, nhưng để đầy đủ, tôi cũng sẽ lưu ý vì đó là một URL, bạn có thể mã hóa !dưới dạng %21, ví dụ curl -v http://example.org/%21132.


13

Điều này cũng có thể làm

curl -v "http://example.org/"'!'"287s87asdjh2/somepath/someresource"
hoặc là
curl -v "http://example.org/"\!"287s87asdjh2/somepath/someresource"

Mà hoạt động vì bash nối các chuỗi liền kề. Cách tiếp cận này đặc biệt hữu ích khi bạn có những thứ khác cần mở rộng shell, vì vậy bạn không thể sử dụng dấu ngoặc đơn cho toàn bộ chuỗi:

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

!ký tự được sử dụng để mở rộng lịch sử trong dấu nhắc dòng lệnh.
vì vậy đây có thể là một vấn đề kịp thời nhưng không phải trong tập tin shell shell.
như bạn có thể thấy mở rộng lịch sử hoạt động ngay cả trong dấu ngoặc kép.


Có rất nhiều cách để tạo các lệnh Unix và các câu tiếng Anh sử dụng nhiều ký tự hơn mức cần thiết và gây nhầm lẫn hơn mức cần thiết. Làm thế nào điều này vượt trội so với câu trả lời đầu tiên / được chấp nhận / được bình chọn cao nhất, cụ thể là, đưa toàn bộ URL vào các trích dẫn duy nhất?
G-Man

2
@ G-Man: Nó cho biết một cách khác để xây dựng các đối số bash. Tôi đã không nhận thức được phương pháp này. Không có gì sai trong việc học những thứ mới.
Sahil Singh

@SahilSingh Cái này mới thế nào? Nó nối ba chuỗi, hai chuỗi được đặt trong dấu ngoặc kép và một chuỗi được đặt trong dấu ngoặc đơn. Không có làm tổ ở đây.
Raphael

@ G-Man Không rõ ràng khi bạn đặt 2 chuỗi cạnh nhau, chúng sẽ được nối với nhau. printf ("hello" "world") cũng sẽ hoạt động trong c, nhưng printf ("hello" 'w') sẽ không hoạt động, vì vậy bạn thấy rằng bash chứa các biểu thức như vậy là mới đối với tôi, nhưng tôi đồng ý từ quan điểm tiện ích, điều này là không vượt trội. Tôi thích câu trả lời, Mark Shust cũng vậy.
Sahil Singh

2
@ G-Man Nó cũng hữu ích khi có các mở rộng chuỗi khác mà người ta muốn xảy ra trong cùng một chuỗi. Đây là một cách dễ dàng để phân tách hai loại hành vi trích dẫn.
WAF

7

Tôi đã gặp một vấn đề tương tự, và giải pháp đơn giản của tôi là sử dụng một biến:

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

Ở đây, sự đơn giản là (1) Nó có thể di động trên các shell và các lệnh (2) Không yêu cầu biết cú pháp thoát và mã ASCII.


3

Kể từ Bash 4.3, bây giờ bạn có thể sử dụng dấu ngoặc kép để trích dẫn ký tự mở rộng lịch sử:

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

điều này không hoạt động bên ngoài echo, tiếng vang dường như tự xử lý việc này khác đi
phil294

@Blauhirn Điều này không liên quan gì đến tiếng vang và mọi thứ phải làm với trích dẫn và phiên bản bash mà bạn đang chạy.
Flimm

2
Câu trả lời này là sai và nên được xóa. bashPhiên bản của bạn không liên quan gì đến tiếng nổ không được mở rộng, do thực tế là trong ví dụ của bạn, phần !tiếp theo là "cuối dòng" và điều đó ngăn vỏ cố gắng mở rộng nó. Hãy thử echo "!Hello World"và bạn sẽ thấy rằng bashsẽ trả lời với bash: !Hello: event not found. Xem hướng dẫn để biết thêm chi tiết
don_crissti

0

Đối với những người đang sử dụng git bash trong windows, câu trả lời được chấp nhận từ @DanielPittman hoạt động. Tuy nhiên, bạn nên thay thế dấu gạch chéo ngược (\) bằng dấu gạch chéo (/).

Ví dụ: trong unix, nó sẽ trông giống như thế này:

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

Đối với các cửa sổ, nó sẽ giống như thế này (tập trung vào dấu gạch chéo về phía trước trong phần tiêu đề ủy quyền)

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


Điều này không có nhiều ý nghĩa. Bạn có một đối số được trích dẫn, do đó, bất kể dấu gạch chéo có liên quan đến exclam sẽ không dẫn đến việc mở rộng lịch sử.
tự đại diện

Ohh bạn đúng. Tôi chỉ đăng câu trả lời này vì khi tôi đang sử dụng câu trả lời của Daniel (sử dụng dấu gạch chéo ngược), một lỗi sẽ xuất hiện.
SamuelDev
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.