bash 소스 코드를 읽고 있는데BNF 구문Bash의 경우 다음과 같습니다.
<pipeline_command> ::= <pipeline>
| '!' <pipeline>
| <timespec> <pipeline>
| <timespec> '!' <pipeline>
| '!' <timespec> <pipeline>
<pipeline> ::=
<pipeline> '|' <newline_list> <pipeline>
| <command>
!
이것은 명령도 일종의 파이프라는 것을 의미합니까 ?
! ls
작동하지만 와 동일합니다 ls
.
! time ls
또한 작동합니다.
이것은 |
파이프와 완전히 다릅니다.
!
Bash에서 어떻게 사용하나요? 파이프인가요?
답변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
마찬가지로,목록;
, &
, 또는 로 &&
연결된 또 다른 파이프 입니다 ||
. 따라서 단일 파이프도 목록이고 단일 명령도 목록입니다. 그런 다음 이와 같은 명령이 take 와 키워드 if
사이의 목록으로 정의 되면 명령 정의의 일부로 단일 명령과 단일 파이프가 자동으로 포함됩니다.if
then
두 개의 파이프로 구성된 목록(그 중 하나에는 하나의 명령만 포함됨):
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
"전체 파이프라인"의 종료 상태만 무효화할 수 있습니다. Cheppner가 지적했듯이 "파이프라인"은 단일 명령이 될 수 있으므로 다음을 수행할 수 있습니다.
! cmd1 && ! cmd2; ! cmd3 || ! cmd4
그러나 이것은 어리석은 일입니다. before는 아무 작업도
!
수행하지cmd2
않습니다. before는 명령 끝의 값!
에만 영향을 미치며 AND와 OR를 교환하여 나머지 두 개를 제거할 수 있습니다.cmd4
$?
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
여기서
Bang
a의%token
값은 입니다'!'
.