stdout을 한 파일로 리디렉션하고 stdout+stderr을 다른 파일로 리디렉션하는 방법은 무엇입니까?

stdout을 한 파일로 리디렉션하고 stdout+stderr을 다른 파일로 리디렉션하는 방법은 무엇입니까?

어떻게 달성할 수 있나요?

cmd >> file1 2>&1 1>>file2

즉, 표준 출력그리고stderr은 하나의 파일(파일 1)로 리디렉션되어야 하며 stdout(파일 2)만 다른 파일로 리디렉션되어야 합니다(둘 다 추가 모드에서)?

답변1

문제는 출력을 리디렉션할 때 다음 리디렉션에 더 이상 사용할 수 없다는 것입니다. tee두 번째 리디렉션의 출력을 보존하기 위해 서브셸에서 파이프를 사용할 수 있습니다 .

( cmd | tee -a file2 ) >> file1 2>&1

또는 터미널에서 출력을 보려면 다음을 수행하십시오.

( cmd | tee -a file2 ) 2>&1 | tee -a file1

tee에 첫 번째 stderr을 추가하지 않으 려면 file1명령의 stderr을 일부 파일 설명자(예: 3)로 리디렉션한 다음 이를 stdout에 다시 추가해야 합니다.

( 2>&3 cmd | tee -a file2 ) >> file1 3>&1
# or
( 2>&3 cmd | tee -a file2 ) 3>&1 | tee -a file1

(@fra-san님 감사합니다)

답변2

그리고 zsh:

cmd >& out+err.log > out.log

추가 모드에서:

cmd >>& out+err.log >> out.log

에서 zsh이 옵션이 비활성화되지 않은 경우 파일 설명자(여기서는 1)가 쓰기를 위해 여러 번 리디렉션될 때 쉘은 출력을 모든 대상에 복사하는 mult_ios내장 함수를 구현합니다 .tee

답변3

다음을 수행할 수 있습니다. stdout을 표시하고(즉, sed -u ...:) stderr도 stdout으로 이동하도록 하고(sed 표시를 통과하지 않기 때문에 표시되지 않음) 생성된 로그 파일에서 2를 구별할 수 있습니다.

다음과 같이: 예느린(예를 들어 while ... ; do ... ; done 대신 perl 스크립트를 사용하면 심각하게 최적화될 수 있습니다. 예를 들어 모든 줄에 하위 쉘과 명령이 생성됩니다!)이상한(한 단계에서 stdout의 이름을 바꾼 다음 다른 단계에서 "실패" stderr를 추가하려면 2개의 {} 단계가 필요한 것 같습니다.) 하지만 그것은 : "개념의 증거", 이는 stdout 및 stderr의 출력 순서를 최대한 유지하려고 시도합니다.

#basic principle (some un-necessary "{}" to visually help see the layers):
# { { complex command ;} | sed -e "s/^/TAGstdout/" ;} 2>&1 | read_stdin_and_redispatch

#exemple:
# complex command = a (slowed) ls of several things (some existing, others not)
#  to see if the order of stdout&stderr is kept

#preparation, not needed for the "proof of concept", but needed for our specific exemple setup:
\rm out.file out_AND_err.file unknown unknown2 
touch existing existing2 existing3

#and the (slow, too many execs, etc) "proof of concept":
uniquetag="_stdout_" # change this to something unique, that will NOT appear in all the commands outputs... 
                     # avoid regexp characters ("+" "?" "*" etc) to make it easy to remove with another sed later on.

{
   { for f in existing unknown existing2 unknown2 existing3 ; do ls -l "$f" ; sleep 1; done ;
   } | sed -u -e "s/^/${uniquetag}/" ;
} 2>&1 | while IFS="" read -r line ; do
    case "$line" in
       ${uniquetag}*) printf "%s\n" "$line" | tee -a out_AND_err.file | sed -e "s/^${uniquetag}//" >> out.file ;; 
        *)            printf "%s\n" "$line"       >> out_AND_err.file ;;   
    esac; 
done;

# see the results:
grep "^" out.file out_AND_err.file

답변4

다양성을 위해:

귀하의 시스템이 이를 지원한다면 /dev/stderr,

(cmd | tee -a /dev/stderr) 2>> file1 >> file2

작동합니다. 표준 출력은 cmd stdout 및 stderr 파이프로 전송됩니다. 표준 오류는 파이프된 stderr을 cmd우회합니다 tee .

그래서

  • 파이프의 표준 출력은 파이프 cmd의 표준 출력 일 뿐입니다.
  • 파이프의 stderr은 cmdstdout과 stderr의 혼합입니다.

그런 다음 이러한 스트림을 올바른 파일로 보내는 것은 간단합니다.

거의 모든 유사한 방법(포함)과 마찬가지로스티븐의 대답), file1이로 인해 선이 제대로 작동하지 않을 수 있습니다.

관련 정보