Bash에서 Bang(!) 사용

Bash에서 Bang(!) 사용

나는 bash 소스 코드를 읽고 있는데,BNF 문법bash의 경우 다음과 같습니다.

<pipeline_command> ::= <pipeline>
                    |  '!' <pipeline>
                    |  <timespec> <pipeline>
                    |  <timespec> '!' <pipeline>
                    |  '!' <timespec> <pipeline>

<pipeline> ::=
          <pipeline> '|' <newline_list> <pipeline>
       |  <command>

!이것은 명령도 일종의 파이프라는 것을 의미합니까 ?

! ls작동하지만 ls.

! time ls작동합니다.

파이프 와는 전혀 다릅니다 |.

!배쉬에서 어떻게 사용하나요 ? 파이프인가요?

답변1

Bash 매뉴얼에서: "예약어 !가 파이프라인 앞에 오면 해당 파이프라인의 종료 상태는 종료 상태의 논리적 부정입니다."

문법을 잘못 읽고 계십니다. 문법에 따르면 ! 파이프라인 앞에서 대체하지 않음 | !.로

답변2

느낌표는 명령/파이프라인의 반환 코드를 논리적으로 반전시킵니다(예:배쉬 매뉴얼):

if true ;    then echo 'this prints' ; fi
if ! false ; then echo 'this also prints' ; fi
if ! true ;  then echo 'this does not print' ; fi

파이프라인의 반환 코드는 (일반적으로) 마지막 명령의 반환 코드이므로 뱅은 이를 반전시킵니다.

if ! true | false ; then echo 'again, this also prints' ; fi

공교롭게도 Bash 소스 배포판에서 해당 BNF 파일을 볼 수 없으며 인용된 문법은 정확하지 않습니다. Bash는 Bash 4.2(2011년 출시) 이후로 여러 번의 앞머리를 허용하기 때문입니다.

if ! ! true ; then echo 'this prints too' ; fi

하지만 그것은 표준이 아닙니다. 예를 들어 zsh와 Dash는 이를 비웃습니다.

답변3

파이프라인 정의하나이상의 명령은 실제로 파이프를 포함하지 않더라도 단일 명령이 파이프라인이기도 함을 의미합니다. 이점은 !부정 연산자로서 명령과 파이프라인에 대해 별도로 정의할 필요가 없다는 것입니다. 파이프라인에 적용하도록 정의하기만 하면 됩니다.

에서는 단일 명령뿐만 아니라 전체 파이프라인의 종료 상태를 무효화 ! cmd1 | cmd2합니다 . 기본적으로 파이프라인의 종료 상태는 가장 오른쪽 명령의 종료 상태입니다.!cmd1


마찬가지로,목록;, &, &&또는 으로 연결된 파이프라인이 하나 더 있습니다 ||. 따라서 단일 파이프라인도 목록이고, 단일 명령도 목록입니다. 그런 다음 다음과 같은 명령이 와 키워드 if사이의 목록을 가져오는 것으로 정의 되면 명령 정의의 일부로 단일 명령과 단일 파이프라인이 자동으로 포함됩니다.ifthen

  • 두 개의 파이프라인으로 구성된 목록(그 중 하나는 하나의 명령으로만 구성됨):

    if IFS= read -r response && echo "$response" | grep foo; then
    
  • 단일 파이프라인으로 구성된 목록:

    if echo "$foo" | grep foo; then
    
  • 단일 파이프라인으로 구성된 목록(자체에는 단일 명령만 포함됨):

    if true; then
    

답변4

다른 답변에 추가할 몇 가지 사항은 다음과 같습니다.

  • (간접적으로) 언급한 바와 같이체프너의 대답에서 연산자 는 가 아닌 구문 요소 !에 대한 선택적 접두사로 정의됩니다 . 이것은 당신이 말할 수 없는 결과를 가져온다<pipeline_command><command>

      cmd1 | ! cmd2
    

    또는

    ! cmd1 | ! cmd2
    

    "전체 파이프라인"의 종료 상태만 무효화할 수 있습니다. Chepner가 지적했듯이 "파이프라인"은 단일 명령이 될 수 있으므로 다음과 같은 작업을 수행할 수 있습니다.

    ! cmd1 && ! cmd2; ! cmd3 || ! cmd4
    

    하지만 그건 어리석은 일이다. 이전은 !아무것도 cmd2하지 않습니다. 이전 !은 명령 끝의 cmd4값에만 영향을 미치며 나머지 두 개는 AND와 OR를 교환하여 제거할 수 있습니다.$?

      cmd1  ||  cmd2;   cmd3  &&  cmd4
    

    마찬가지로 while ! cmd로 대체할 수 있습니다 until cmd.

  • <pipeline>a가 앞에 오는 A는 - 다른 구문 요소 !가 됩니다 . <pipeline_command>그러므로 다음과 같이 말하는 것은 타당하지 않습니다.

    ! ! cmd1
    

    와 같은 것이 유효한 산술 확장과는 다릅니다.$((! ! value))$((! ! ! value))

  • 다음 사항을 주의하세요.POSIX동일한 문법을 ​​정의하지만 다른 요소 이름을 사용합니다. 문제의 BNF는 POSIX에서 다음과 같이 나타납니다.

    pipeline         :      pipe_sequence
                     | Bang pipe_sequence
    
    pipe_sequence    :                             command
                     | pipe_sequence '|' linebreak command
    

    값이 있는 a 는 어디에 Bang있습니까 ?%token'!'

관련 정보