강타를 울리는 법!


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
또한 문자열 보간을 비활성화합니다 :(
Hubro

그게 요점입니다! 큰 따옴표를 사용하여 동일한 echo 명령에 다른 인수를 추가하고 해당 부분에 대한 보간을 얻을 수 있습니다.
Richm

3
와 함께 bash에서 C 스타일 문자열을 사용할 수도 있습니다 $''. 예를 들어, echo $'1!\n2!\n3!\n'각 숫자 다음에 뱅과 줄 바꿈이 인쇄됩니다.
spelufo

1
여러 줄 문자열을 입력 할 때 작은 따옴표로 묶는 것은 도움이되지 않았습니다.! 강타-작은 따옴표는 강타를 피하지 않습니다 (실제)
binki

1
@kbolino 당신이 맞아요. 따라서 전체 예제 문자열은 다음과 같습니다. echo '0123'"$var"'456', 두 쌍의 작은 따옴표와 한 쌍의 큰 따옴표.
phyatt

16

으로 Richm 말했다 , 배쉬는 어떻게하려고 역사의 일치 . 그것을 피하는 또 다른 방법은 \다음 과 같이 강타를 피하는 것입니다 .

$ echo \#\!/bin/bash
#!/bin/bash

큰 따옴표 안에는 있지만 \제거되지 않습니다.

$ echo "\!"
\!

8
bash에서는 "\!"실제로 POSIX 호환을 위해로 확장 \!되지 않습니다 !.
Mikel

@Mikel Sigh. zsh와 bash의 많은 차이점
Michael Mrozek

여러 줄 문자열을 입력 할 때도 작동합니다. 뱅을 입력 할 때 1. 문자열 외부에 있어야합니다.
binki

1
bash는 스크립트를 실행할 때 히스토리 검색을 수행하지 않으므로 특별한 작업을 수행 할 필요가 없습니다.
binki

!마법의 행동없이 큰 따옴표 안에 이스케이프하는 구문이 없습니까? 이것은 견과류입니다 ...
Lassi

13

!히스토리 대체를 시작합니다 ( "이벤트"는 명령 히스토리의 행입니다). 예 !ls함유 마지막 명령 라인 확장 ls!?foo포함 된 마지막 명령 라인 확장 foo. 특정 단어 (예 : !!:1이전 명령의 첫 단어 참조) 등을 추출 할 수도 있습니다 . 자세한 내용은 설명서를 참조하십시오.

이 기능은 커맨드 라인 에디션이 기본이었던 시절에 이전 명령을 빠르게 리콜하기 위해 개발되었습니다. 최신 셸 (최소한 bash 및 zsh)과 복사하여 붙여 넣기를 사용하면 기록 확장이 이전처럼 유용하지는 않습니다. 여전히 도움이되지만 도움이되지 않아도 얻을 수 있습니다.

histchars변수 를 설정하여 히스토리 대체를 트리거하는 문자를 변경할 수 있습니다 . 히스토리 대체를 거의 사용하지 않는 경우, 대신 히스토리 확장 histchars='¡^'¡트리거 하도록 예를 설정할 수 있습니다 !. 로 기능을 완전히 끌 수도 있습니다 set +o histexpand.


3

특정 명령 행에서 히스토리 확장을 사용하지 않으려면 다음 space의 세 번째 문자로 사용할 수 있습니다 $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.

두 기능을 모두 원치 않는 경우의 세 번째 문자로 다른 문자를 선택해야합니다 $histchars. 명령 해석 방식에 영향을 미치지 않는 것을 원합니다. 몇 가지 옵션 :

  • 백 슬래시 사용 ( \) : \echo foo작동하지만 별명 또는 키워드를 사용하지 않는 부작용이 있습니다.
  • 탭 : 첫 번째 위치에 삽입하려면을 눌러야 Ctrl+VTab합니다.
  • 당신이 두 개의 키를 입력 괜찮다면, 당신은 일반적으로 첫 번째 위치에 표시 (하지 않는 문자를 선택할 수 있습니다 %, @, ?, 자신의 선택)과 그것을 위해 빈 별칭을을 :

    histchars='!^%'
    alias %=

    그런 다음 해당 문자, 공백 및 명령을 입력하십시오.

    bash-4.3$ % echo !!
    !!

(당신이 역사를 대체 그래도 비활성화 된 명령을 기록 할 수 없습니다 할 수 없습니다. 또한 기본 3 문자주의 $histchars입니다 #당신이 그것을 변경하는 경우. 그래서 역사 확장 댓글에서 수행되지 않으며, 당신은에 설명을 입력 프롬프트에서! 시퀀스가 ​​확장 될 수 있다는 사실을 알고 있어야합니다.


2

제안 된 솔루션은 다음 예에서 작동하지 않습니다.

$ bash -c "echo 'hello World!'"
-bash: !'": event not found
$

이 경우 bang은 8 진 ASCII 코드를 사용하여 인쇄 할 수 있습니다.

$ bash -c "echo -e 'hello World\0041'"
hello World!
$

1
첫 번째 명령에서는 !큰 따옴표 사이에 있으며 다른 답변에서 히스토리 확장 의미를 유지합니다. 당신은 사용할 수 있습니다 bash -c 'echo '\''hello World!'\'또는 bash -c "echo 'hello World"\!"'".
Gilles

-i 매개 변수가 없으면 ~ / .profile이 실행되지 않는 것처럼 환경이 변경 될 수 있습니다. 그러나 -i를 수행하면 .profile의 출력이 실제로 실행하려는 명령의 출력에 캡처됩니다.
Brent

-1

Bash 4.3 이후로 이제 큰 따옴표를 사용하여 내역 확장 문자를 인용 할 수 있습니다.

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

4
아니요, 그 !뒤에는 "더 이상 특별하지 않습니다. echo "foo!"괜찮 echo "foo!bar"되지 않는다
스테판 Chazelas가
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.