명령이 성공한 경우에만 출력을 억제하려면 어떻게해야합니까?


22

일반적으로 성공적인 보조 명령의 출력을 억제하여 스크립트 출력을 단순화하고 싶습니다.

그러나 -q그것들을 사용 하면 때때로 실패 할 때 출력을 숨기므로 오류를 이해할 방법이 없습니다. 또한이 명령은 출력을에 로그온합니다 stderr.

명령 이 성공한 경우에만 명령의 출력을 억제하는 방법이 있습니까?

예를 들면 다음과 같습니다 (단, 이에 한하지 않음).

mycommand | fingerscrossed

모든 것이 잘 진행 fingerscrossed되면 출력을 잡아서 버립니다. 그렇지 않으면 표준 또는 오류 출력 (무엇이든)에 반영됩니다.

답변:


36

moreutils' chronic명령은 다음을 수행합니다.

chronic mycommand

mycommand실패하지 않는 한 출력 을 삼켜 서 출력이 표시됩니다.


1
고맙습니다. 대부분의 유닉스 OS에 기본적으로 설치되어 있지 않다고 생각합니까?
Matthieu Napoli

1
널리 패키지되어 있지만 설치가 쉽지는 않지만 아마도 아닙니다.
Stephen Kitt

1
데비안은 패키지 안에있다 moreutils. 어쨌든 나를 위해 좋은 :)
Tom Zych

6
전체 출력을 메모리에 저장합니다.
Stéphane Chazelas

1
@ StéphaneChazelas는 이와 같은 것을 구현하는 유일한 방법 일 수 있으므로 명령이 필요할 때 출력을 저장해야합니다.
Centimane

11
### do this bit once at the top of your script
divert=
exec 3<>"${divert:=$(mktmp)}" 4<>/dev/null
rm -- "$divert"; unset divert
### then do this bit as often as needed
command >&3 2>&3
cat <&3 >&"$(((RTN=$?)?2:4))"

아마도 트릭을해야합니다. 각각의 출력을 command삭제 된 임시 파일로 버퍼링 한 후 /dev/null리턴 상태가 0이 아닌지 여부에 따라 출력을 하나 또는 stderr 로 사이펀 합니다. 임시 파일은 미리 삭제되기 때문에 어떤 프로세스에서도 현재 디스크와 그 자식을 파일 설명자에서 읽을 수 없으며 ( /proc/$pid/fd적절한 권한이있는 몰래 스 누프 제외) 끝날 때 정리할 필요가 없습니다.

아마도 리눅스 시스템에서보다 편리한 솔루션 일 것입니다 :

divert(){
    "$@" >&3 2>&3 ||
    eval "cat <&3
          return $?"
}   3<<"" 3<>/dev/fd/3

... 대부분의 쉘에서 다음과 같이 호출 할 수 있다는 점을 제외하면 다른 쉘과 매우 유사하게 작동합니다 divert some simple-command with args. 높은 출력 명령을 조심 "$@"하지만 위해 dash, yash또는 파이프 여기-문서를 할 다른 쉘 - 나는 파이프 버퍼 채우기 위해 그 껍질에 가능하다 생각 (linuxes에 주위의 1백28킬로바이트의 기본에서)을 하고 교착 상태 때문에 . 즉에 대한 걱정 안 ksh, mksh, bash, zsh불구 또는 Bourne 쉘 - 그 모두가 기본적으로 같은 일을 내가 명시 적으로 위처럼 exec.


9

일반적으로 오류가 발생하면 명령이 메시지를 출력 stderr하므로 작업을 수행하기 위해stdout

mycommand > /dev/null


고맙지 만 질문에서 말했듯이 내 명령은 모든 출력을 기록 stderr하므로 아무런 영향을 미치지 않습니다.
Matthieu Napoli

4

자신의 만성을 만들기 위해

my_chronic() {
  tmp=$(mktemp) || return # this will be the temp file w/ the output
  "$@"  > "$tmp" 2>&1 # this should run the command, respecting all arguments
  ret=$?
  [ "$ret" -eq 0 ] || cat "$tmp"  # if $? (the return of the last run command) is not zero, cat the temp file
  rm -f "$tmp"
  return "$ret" # return the exit status of the command
}

3

내 makefile에서 이와 같은 작업을 수행합니다.

if (mycommand) &> mycommand.log; then 
  echo success 
else 
  c=$?; 
  echo;echo -e "Bad result from previous command, see mycommand.log for more details";echo;
  command_to_run_on_fail
  (exit $c)
fi

상황에 맞게 다음과 같이 할 수 있습니다.

if ! (mycommand) &> mycommand.log; then 
  c=$?; 
  cat mycommand.log
  rm mycommand.log
  (exit $c)
fi

따라서 "if"는 명령을 실행하고 출력을 mycommand.log로 파이프합니다. stdout vs stdout vs 무엇이든 잡아야하는 경우 파이프 명령 '&>'을 '>'로 변경해야 할 수도 있습니다. 명령이 실패하면 오류 코드를 캡처하고 mycommand.log의 내용을 인쇄하고 mycommand.log를 제거한 후 원래 오류 코드와 함께 리턴하십시오.

(exit $ c)가 없으면 'rm'명령이 반환 한 것과 일치하는 종료 코드와 함께 반환됩니다.

마지막으로, 하나의 라이너를 원한다면 이와 같은 것이 효과적입니다.

mycommand &> mycommand.log || cat mycommand.log; rm mycommand.log

2
당신은 정말로 당신의 명령들 등을 포장합니까? 에 (...)그런? 그것은 당신에게 유용한 일을하지 않고 여분의 서브 쉘을 생성하기 때문입니다.
Etan Reisner

@EtanReisner (exit $c)가 설정 $?중입니다. 다른 방법으로는 할 수 없습니다. if ! (mycommand) &>x명령이 eg를 사용 time하거나 쉘 오류를 발생시키는 경우 경로 재 지정에 의미 가 있습니다.
Michael Homer

@MichaelHomer-그 것들을 위해 curlies가 있습니다 { ; }... 그러나 exit약간 까다 롭습니다.
mikeserv 2016 년

makefile 스 니펫에서 이전에 저장된 상태로 종료하려고 $?하면 사용할 수 exit $c있지만 다른 경우 (exit $?)에는 가치가 있습니다 (쉘 기능 rret() { return $1; }이 일반적으로 더 좋을 수도 있지만 논쟁의 여지가 있습니다). mikeserv에 표시된 것처럼 명령의 하위 셸은 여전히 ​​실제로는 아닙니다.
Etan Reisner 2016 년

3

나는 이 다른 질문대해 훨씬 간단한 대답을 찾았습니다 .

output=`mycommand 2>&1` || echo $output

매력처럼 작동합니다!


참고 : 사용 사례의 경우이 방법이 훨씬 더 간단한 솔루션 (모든 CI 서버에 추가 항목을 설치하지 않음)이므로이 옵션을 허용 된 것으로 표시했습니다. YMMV.
Matthieu Napoli

쉘 스크립트에서 set -o xtrace를 사용하면 할당 output = ... :-)의 세부 사항을 로깅하는 일부로 모든 출력이 다시 나타납니다. 이 경우 만성을 사용하는 것이 좋습니다.
Jan-Philip Gehrcke
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.