zsh에서 오류 메시지를 억제하는 방법은 무엇입니까?

zsh에서 오류 메시지를 억제하는 방법은 무엇입니까?

zsh에서

  • rm foo.bar인쇄합니다 rm: foo.bar: No such file or directory.
  • rm foo.bar 2>/dev/null예상대로 아무것도 인쇄되지 않습니다.

그러나 명령에 패턴 일치가 포함되어 있으면 다음을 통해 오류가 억제되지 않습니다 2>/dev/null.

  • rm *.bar인쇄합니다 zsh: no matches found: *.bar.
  • rm *.bar 2>/dev/null같은 것을 인쇄합니다.

zsh에서 오류 메시지를 억제하는 일반적인 방법이 있습니까? 하나단순한모든 종류의 오류 메시지에 대한 방법입니다.

답변1

실행하려고 하는데 rm *.bar일치하는 파일이 없으면 *.bar기본적으로 두 가지 일이 발생할 수 있습니다.

  • POSIX 동작은 쉘이 rm리터럴을 *.bar인수로 사용하여 실행되는 것입니다. 이 도구는 문자 그대로 이름이 지정된 파일을 제거하려고 시도하지만 *.bar(를 실행하는 것처럼 rm '*.bar') 실패하고 다음과 같은 내용을 인쇄합니다 rm: *.bar: No such file or directory. 이것이 POSIX 쉘( sh)과 호환 쉘이 작동하는 방식입니다.

  • POSIX가 아닌 동작은 쉘이 일치하는 항목이 없음을 감지하고 다음과 같은 것을 인쇄하고 no matches found: *.bar실행되지 않는 것입니다.rm 조금도. 이것이 Zsh가 기본적으로 작동하는 방식입니다. (비교를 위해 Bash에서는 를 사용하여 이 동작으로 전환할 수 있습니다 shopt -s failglob.)

(이전 경우) 의 오류가 의 rmstderr에 인쇄됩니다 rm. 쉘의 오류(후자의 경우)는 쉘의 표준 오류에 인쇄됩니다.

리디렉션은 +rm *.bar 2>/dev/null 의 표준 오류 rm에만 영향을 미칩니다 . 귀하의 예에서는 실행되지도 않습니다.rm

메인 쉘의 stderr을 리디렉션하려면 exec. "메인 셸"이란 사용자가 입력하는 대화형 셸을 의미합니다. 또는 스크립트를 실행하는 경우 스크립트를 해석하는 쉘입니다. 예:

exec 2>/dev/null

Zsh에서는 닫을 수도 있습니다.

exec 2>&-

합리적인 접근 방식은 나중에 사용(또는 복원)해야 하는 경우를 대비하여 원본 stderr을 미리 복제하는 것입니다. 예(이 코드를 대화형 Zsh에 붙여넣으려면 다음을 호출해야 합니다.setopt interactive_comments첫 번째):

exec 7>&2           # "save" stderr
exec 2>/dev/null    # redirect
rm *.bar
whatever
exec 2>&7           # restore
exec 7>&-           # close descriptor which is no longer needed

다음은 7임의의 한 자리 숫자입니다. 그렇지 않으면 파일 설명자로 사용되지 않습니다. 처음 두 줄은 하나로 쓸 수 있습니다: exec 7>&2 2>/dev/null; 마찬가지로 마지막 두 줄도 가능합니다.

stderr 리디렉션 없이 호출된 참고 rm또는 모든 명령(예: whatever)은 셸에서 stderr을 상속합니다. 이는 위의 예 rm(실행된 경우) 를 의미하며 whatever오류 메시지(있는 경우)를 에 인쇄합니다 /dev/null. 임의의 숫자나 명령을 호출 하면 exec 2>/dev/null모두 /dev/nullstderr로 갖게 됩니다. 모든 종류의 오류 메시지를 정말로 표시하지 않으려면 이 방법을 사용하세요.

이 솔루션은 Zsh뿐만 아니라 많은 셸에서 작동합니다. 대화형 셸의 stderr를 리디렉션하려면 덜 정교한 일부 셸에서는 stderr을 사용하여 프롬프트를 인쇄한다는 점을 명심하세요.

프로세스는 자체 표준 오류를 리디렉션할 수 있습니다(셸에서 처럼 exec 2>…). 또는 stdout이나 to로 오류 메시지를 인쇄할 수 있습니다 /dev/tty(그렇지 않아야 하지만 기술적으로는 가능합니다). 그러므로exec 2>/dev/null~ 아니다오류 메시지처럼 보이는 메시지가 표시되지 않도록 보장합니다.

그 후에도 exec 2>/dev/null요청 시 모든 명령의 stderr를 리디렉션할 수 있습니다. 예를 들어 다음과 같은 경우 whatever가 있습니다.

whatever 2>&7

그러면 오류 메시지는 의도적으로 파일 설명자로 저장한 원본 stderr로 이동됩니다 7.


exec쉘의 stderr(또는 다른 파일 설명자)를 리디렉션하는 유일한 방법은 아닙니다. rm에서 처리하는 것처럼 쉘(전체 메인 쉘은 아님)을 처리할 수 있습니다 rm … 2>/dev/null. 서브쉘을 다음과 같이 처리할 수 있습니다:

( rm *.bar ) 2>/dev/null

또는 메인 셸에서 해석되는 일부 코드일 수도 있습니다.

{ rm *.bar; } 2>/dev/null

( ;여기서는 Zsh에서는 선택 사항이고 다른 일부 셸에서는 필수입니다. 코드가 Zsh 외부에서도 작동하기를 원했습니다.)

이 라인 중 하나가 문제를 해결할 수 있습니다. 쉘에서 나오는 오류 메시지를 억제하는 맥락에서 두 줄은 ++ 와 동일합니다 .

리디렉션은 (/ 에서 시작하고 / {에서 끝나며 범위가 제한됩니다. 여전히 괄호 안에 많은 명령을 넣을 수 있으므로 "제한된" 범위는 실제로 전체 스크립트일 수 있습니다. 또는 스크립트의 일부일 수도 있습니다( 이 답변의 앞부분에 소개된 내용 포함). / 이후 리디렉션이 작동하지 않는다는 사실 은 이 접근 방식을 .)}whatever)}exec


+rm 엄밀히 말하면, 가 되기 전과 후에 " "에 영향을 미칩니다 rm. 참아주세요. 리디렉션은 rm … 2>/dev/null다음에 의해 수행되는 리디렉션으로 시작됩니다.rm실행 파일 로 자신을 대체하려는 분기된 셸. 이 쉘은 자신을 rm. 리디렉션을 수행한 후 보고되는 모든 오류는 로 이동됩니다 /dev/null. 예를 들어 rm찾을 수 없는 경우 이미 수행된 리디렉션은 command not found오류를 억제합니다.

++ 기술적으로 ( … )서브쉘을 생성 { … }하지 않습니다. 서브셸은 변수와 현재 작업 디렉터리를 상속하는 별도의 셸 프로세스처럼 동작하지만 상위 셸에서 아무것도(변수나 현재 작업 디렉터리 등) 변경할 수 없습니다. 이는 완전히 별도의 프로세스로 실현될 수도 있고 실현되지 않을 수도 있습니다. 중요한 것은 동작입니다. OTOH는 { … }특정 목적으로만 명령을 그룹화합니다(우리의 경우 목적은 리디렉션입니다). 이는 사용할 때 하위 쉘이 전혀 없다는 의미는 아닙니다 { … }. 예를 들어 파이프라인에서 마지막 부분을 제외한 모든 부분은 어쨌든 서브쉘입니다(일부 쉘에서는 마지막 부분을 포함한 모든 부분). 이러한 기술적 세부 사항은 우리 문제의 맥락에서만 관련이 없지만 일반적으로 차이를 만들 수 있습니다.

관련 정보