Cái gì là -bash :! '': không tìm thấy sự kiện "


114

Hãy thử thực hiện các thao tác sau dưới vỏ bash echo "Reboot your instance!"

Về cài đặt của tôi:

root@domU-12-31-39-04-11-83:/usr/local/bin# bash --version
GNU bash, version 4.1.5(1)-release (i686-pc-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
root@domU-12-31-39-04-11-83:/usr/local/bin# uname -a
Linux domU-12-31-39-04-11-83 2.6.35-22-virtual #35-Ubuntu SMP Sat Oct 16 23:57:40 UTC 2010 i686 GNU/Linux
root@domU-12-31-39-04-11-83:/usr/local/bin# echo "Reboot your instance!"
-bash: !": event not found

Bất cứ ai có thể vui lòng giải thích "sự kiện bash là gì?" Tôi chưa bao giờ nghe khái niệm này trước đây. Ngoài ra, làm thế nào tôi nên xuất "!" ở cuối câu?

Câu trả lời:


53

Bạn có thể tắt thay thế lịch sử bằng cách sử dụng set +H.


2
Bạn có biết lý do đằng sau cú pháp? Có vẻ như thực sự phản trực giác. Bạn sẽ nghĩ rằng mình gõ +Hđể kích hoạt một cái gì đó và -Hvô hiệu hóa một cái gì đó.
Phường Gavin

7
@PunkyGuy: Tôi không biết lịch sử (ý định chơi chữ) đằng sau nó, nhưng các tùy chọn Unix thường bắt đầu bằng dấu gạch nối (hoặc dấu trừ) và +đơn giản là ngược lại với điều đó.
Dennis Williamson

105

!là một ký tự đặc biệt để bash, nó được sử dụng để chỉ các lệnh trước đó; ví dụ,

!rm

sẽ gọi lại và thực thi lệnh cuối cùng bắt đầu bằng chuỗi "rm" và

!rm:p

sẽ gọi lại nhưng không thực thi lệnh cuối cùng bắt đầu bằng chuỗi "rm". bash đang diễn giải dấu chấm than echo "reboot your instance!"thành " thay thế ở đây lệnh cuối cùng bắt đầu bằng (các) ký tự ngay sau dấu chấm than " và càu nhàu với bạn rằng nó không thể tìm thấy một sự kiện (lệnh) trong lịch sử của bạn bắt đầu bằng một báo giá kép.

Thử

echo reboot your instance\!

để bảo vệ (thoát) dấu chấm than khỏi bash.


Có, nhưng sẽ xảy ra nếu tôi muốn sử dụng echo -e "một số văn bản $ ENV_VAL một số văn bản khác \ nReboot ngay bây giờ!" ?
Maxim Veksler

1
Viết hai câu lệnh echo; bạn nhận được linefeed miễn phí.
MadHatter

1
Giải pháp đơn giản là sử dụng dấu ngoặc đơn và dấu ngoặc kép cùng một lúc: echo -e "Text \ nReeboot" '!'
mmey

4
Điều này thật tệ Nếu tôi không thoát khỏi dấu chấm than, bash sẽ ném vừa. Nếu tôi làm thoát khỏi nó, dấu chéo ngược được bao gồm trong chuỗi thức. Tại sao bạn làm điều này, Bash !! ( pastebin.com/g4PYv56A )
Hubro

2
@Hubro công bằng, tôi không chắc đó là lỗi của bash. Bạn có một số vấn đề phức tạp bằng cách sử dụng ruby ​​để nuôi mọi thứ để bash, và đối với tôi không rõ phần nào ruby ​​đang chơi trong việc tước hoặc củng cố các nhân vật trốn thoát.
MadHatter

25

Để giải quyết vấn đề ban đầu của bạn, hãy thử sử dụng dấu ngoặc đơn, thay vì dấu ngoặc kép. Với cái sau, bash sẽ cố gắng mở rộng một số ký tự nhất định trước khi chuyển kết quả cho lệnh (echo trong trường hợp này). Với dấu ngoặc đơn, bash vượt qua toàn bộ chuỗi, không thay đổi.

!được sử dụng trong các lệnh để tham khảo lịch sử dòng lệnh. Xem: http://tldp.org/LDP/abs/html/abs-guide.html#HISTCOMMANDS để có một bộ đầy đủ. Với ví dụ trên, bash đang cố gắng mở rộng !"như một tham chiếu đến một sự kiện trước khi echo xuất hiện, do đó xảy ra lỗi.

Lưu ý rằng trong các tập lệnh, tất cả các lệnh lịch sử đều bị tắt, vì chúng chỉ có ý nghĩa trong một vỏ tương tác.

Người duy nhất tôi sử dụng một cách thường xuyên, là !$. Nó mở rộng đến đối số cuối cùng của lệnh trước đó. Đó là một tốc ký hữu ích ở những nơi.


4
!!để điền vào lệnh hoàn chỉnh cuối cùng được nhập là rất hữu ích; đặc biệt, sudo !!hoặcpfexec !!
jgoldschrafe

2
Tôi cũng thấy sudo và pfexec là những tiện ích tốt, nhưng không cần phải quá nhiệt tình.
LeartS

$_hoạt động trong nhiều shell hơn bash và đó là một biến thích hợp, không giống như !$. (và @LeartS: Tôi thích thiếu của trò đùa của bạn biểu tượng cảm xúc;.))
ΤΖΩΤΖΙΟΥ

7

Chỉ cần đặt một khoảng trống giữa! và "hơn nó sẽ làm việc.

Chúc mừng.


2
Bạn có thể vui lòng thêm một lời giải thích về lý do tại sao giải pháp của bạn hoạt động?
200_success

2
Điều này hoạt động vì Bash chỉ xử lý! như một ký tự đặc biệt nếu nó được theo dõi trực tiếp bởi một ký tự không phải khoảng trắng. Tuy nhiên, nó cũng sẽ thêm một khoảng trống vào đầu ra của bạn, do đó có thể không phải lúc nào cũng được mong muốn ...
mmey

2

Đúng, ! là một ký tự đặc biệt để bash, nó được sử dụng để chỉ các lệnh trước đó.

Vài cách bạn có thể xử lý tình huống

Sau đây sẽ xuất ra chuỗi như nó là

echo 'Reboot your instance!'

Sau đây sẽ thực hiện lệnh và nối chuỗi

echo 'escaping #'" adding `which python` to the string"
echo '#!'`which python`

1

Trong bash 4.3có vẻ như bạn không còn cần phải sử dụng dấu ngoặc đơn hoặc set +H:

$ bash --version
GNU bash, version 4.3.46(1)-release (x86_64-unknown-linux-gnu)
[...]
$ echo "Reboot your instance!"
Reboot your instance!

Có lẽ là một lỗi, bởi vì ở đây, tôi có 4.4.12 và một lần nữa, tôi cần set +Hhoặc trích dẫn. Hoặc bạn có set +Hmột nơi nào đó (như trong /etc/profile).
Bodo Thiesen

Sử dụng! -Không ở cuối câu để xác minh phát hiện sự kiện của bash vẫn hoạt động tốt. Phiên bản là 4.3.30 ........ $ echo "Kiểm tra lại câu của bạn! Foo" bash :! Foo: không tìm thấy sự kiện
JohnnyD92

0

Bạn cũng có thể sử dụng một di truyền :

cat <<EOF
Reboot your instance!
EOF

Nó gây khó chịu trong trường hợp này bởi vì nó không phải là một lớp lót mà cho các lệnh dài hơn (như viết một tập lệnh bash), nó hoạt động rất tốt.

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.