큰 따옴표 안에 느낌표가 왜 Bash 오류를 발생 시키는가?


25

다음 명령을보십시오 :

$ notify-send SYNC TIME!
$ notify-send 'SYNC TIME!'
$ notify-send "SYNC TIME!"
bash: !": event not found
$

처음 두 명령은 예상대로 알림 풍선을 생성합니다. 세 번째는 표시된 오류를 나타냅니다.

$ echo SYNC TIME!
SYNC TIME!
$ echo 'SYNC TIME!'
SYNC TIME!
$ echo "SYNC TIME!"
bash: !": event not found
$

여기에서도 echo처음 두 명령에 대해서는 작동하지만 세 번째 명령 에는 작동하지 않습니다.

더 (I이 사용에 계획하지 않았더라도) 여기 문제 : 모두 notify-send "SYNC!TIME"echo "SYNC!TIME"주고 bash: !TIME": event not found.

그러나 모두 notify-sendecho작품에"SYNC! TIME"

누군가 bash: !": event not found오류가 나타나는 이유를 설명해 주 시겠습니까?

답변:


31

!Bash의 기본 기록 확장 문자입니다. Bash 맨 페이지의 "HISTORY EXPANSION"섹션을 참조하십시오.

  • !에서처럼 작은 따옴표로 묶인 경우 기록 확장이 발생하지 않습니다 .

    notify-send 'SYNC TIME!'
  • 에서와 !같이 공백, 탭, 줄 바꿈, 캐리지 리턴 또는이 뒤에 있으면 히스토리 확장이 수행되지 않습니다 =.

    notify-send SYNC TIME!
  • 역사 확장은 하지 걸릴 장소를

    echo "SYNC TIME!"

    "기록에서 시작하는 명령이 없으면 오류가 발생합니다.


4
이 오작동은 .bashrc라인 에 추가하여 해결할 수 있습니다 set +H. 참고 !이미 스크립트 아닌 특별하다; 특수한 것으로 취급하면 많은 표준 준수 스크립트가 손상됩니다. 대화식 쉘에서는 "특별한"것으로 취급되며,이를 수정하기 전까지는 기본적으로 만 사용됩니다. :-)
R ..

15

bash에서 !예약어 (OK, character)이기 때문에 다른 문맥에서 특별한 의미가 있습니다. 이 특별한 경우에, 당신은 역사 검색에서 그 중요성을 무시하고 있습니다. 보낸 사람 man bash:

   History expansions introduce words from the history list into the input
   stream, making it easy to repeat commands, insert the  arguments  to  a
   previous command into the current input line, or fix errors in previous
   commands quickly.

  [...]

   History expansions are introduced by
   the appearance of the  history  expansion  character,  which  is  !  by
   default.   Only  backslash  (\) and single quotes can quote the history
   expansion character.

기본적으로 이것은 bash가 뒤에 문자를 가져 와서 해당 문자로 !시작하는 첫 번째 명령에 대한 기록을 검색한다는 것을 의미합니다. 설명하는 것보다 설명하기가 더 쉽습니다.

$ echo foo
foo
$ !e
echo foo
foo

!로 시작하는 첫 번째 명령 일치 활성화 역사 확장, e이는 이전에 실행 한 echo foo후 다시 실행 된합니다. 따라서 "SYNC TIME!"bash는을 (를 !") 검색 했을 때, (으)로 시작하는 명령에 대한 검색 기록을 보고 "실패했으며 이에 대해 불평했습니다. 예를 들어을 실행하면 동일한 오류가 발생할 수 있습니다 !nocommandstartswiththis.

느낌표를 인쇄하려면 다음 두 가지 방법 중 하나로 느낌표를 이스케이프해야합니다.

echo 'Hello world!'
echo Hello world\!

6
echo Hello world!역사 확장은 공백에 의해 트리거되지 않습니다 ;-) (아, 멋진 코너 사례 ...)
Rmano

1
그러나 느낌표를 공백보다 이스케이프 처리하는 것이 좋습니다.
Ehtesh Choudhury

1
@Rmano 변화가 가능한 행동을 안내하는 것이 아니라 명시 적으로 말하는 것을 선호합니다
Braiam

!A는 예약어bash로, POSIX는 선언한다 . 그러나 나는 역사 확장에서의 역할 과 완전히 무관 하며 큰 따옴표로 처리하는 것과는 관련이 없다고 확신 합니다. !명령 / 파이프 라인의 종료 상태를 무효화하기 때문에 예약어이므로 명령으로 사용할 수 없습니다. 다른 예약어는 특별하지 않습니다 "동안, -quoted 상황 $입니다 하지 예약어하지만 되어 특별하게 처리.
Eliah Kagan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.