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


32

어떻게 달성 할 수 있습니까

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

즉, stdout stderr는 하나의 파일 (file1)로 리디렉션해야하고 stdout (file2) 만 다른 파일로 리디렉션해야합니까 (둘 다 추가 모드에서)?

답변:


41

문제는 출력을 리디렉션 할 때 다음 리디렉션에 더 이상 사용할 수 없다는 것입니다. tee서브 쉘로 파이프 하여 두 번째 경로 재 지정에 대한 출력을 유지할 수 있습니다 .

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

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

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

최초의 표준 오류를 추가 방지하기 tee위해 file1, 당신은 어떤 파일 기술자 (예 : 3)에 명령의 표준 오류 리디렉션, 나중에 다시 표준 출력하려면이 옵션을 추가해야합니다 :

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

(@ fra-san 덕분에)


16

zsh:

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

추가 모드에서 :

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

에서 zsh1, 제공된 mult_ios파일 기술자 (여기 1) 쓰기를 위해 여러 번 리디렉션 할 때 옵션을 비활성화되지 않았습니다 후 쉘 구현 내장 된 tee모든 대상에 출력을 복제 할 수 있습니다.


나는 여기서 무엇 out+errout의미 하는지 알 수 없습니다 . 파일명? 스트림을 리디렉션 하시겠습니까?
gronostaj

@gronostaj 명령이 다음과 같이 생각된다cmd >& file1 > file2
Isaac

이 솔루션은 출력이 생성 된 순서를 유지합니다. 실제로 stdout과 stderr을 (순서대로) 저장하려면 다른 접근법이 필요합니다.
이삭

1
@Isaac, stdout 출력이 파이프를 통해 (각 파일로 전달하는 프로세스로) stderr 출력이 파일로 직접 이동하므로 순서가 반드시 유지되지는 않습니다. 어쨌든 OP가 stderr 출력이 stdout 출력 다음에 오도록 요청한 것처럼 보이지 않습니다.
Stéphane Chazelas

3

다음과 같이 할 수 있습니다. stdout에 태그를 지정하십시오 (UNBUFFERED sed 사용). sed -u ... stderr에 stdout (태깅 sed를 거치지 않았으므로 태그가 지정되지 않음)으로 이동하여 결과 로그 파일에서 2를 구분할 수 있습니다.

다음은 :입니다 느린 (; 할 ...; 그것은 심각 대신하면서 ...의 exemple 펄 스크립트를 사용하여, 최적화 할 수있는 모든 라인에서 서브 쉘 및 명령을 산란 것, exemple를 들어, 다!), 이상한 에 ": 등, 그러나 그것이 (내가 하나 개의 이름 바꾸기 표준 출력에 다음 다른 하나의 그것에 표준 오류"를 통해 오리엔트 "추가하려면 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

이것은 실제로 이해하기 어렵습니다. (1) 왜 복잡한 사용 사례 ( ls unknown)를 사용 하여 stderr에 무언가를 인쇄합니까? >&2 echo "error"괜찮을 것입니다. (2) tee한 번에 여러 파일을 추가 할 수 있습니다. (3) 왜 cat대신에 grep "^"? (4) stderr 출력이로 시작하면 스크립트가 실패합니다 _stdout_. (5) 왜?
pLumo

@RoVo : 첫 번째 주석 처리 된 행은 개념 증명 예제보다 간단한 알고리즘을 보여줍니다. 1) : 이것은 ls loopstdout과 stderr의 출력을 제어 된 순서로 혼합 (대안 적으로)하여 stdout의 태그 지정에도 불구하고 stderr / stdout 순서를 유지했는지 확인할 수 있습니다. 2) : gnu tail, 아마도, 그렇지 않습니다 규칙적인 꼬리 (예 : aix.). 3) : grep "^"에도 두 파일 이름이 모두 표시됩니다. 4) : 변수에 의해 변경 될 수 있습니다. 5) : 복잡한 예제는 내가 테스트 한 오래된 oses (ex, old aix)에서 작동합니다 (사용 가능한 펄 없음).
Olivier Dulac

(1) stderr과 stout에 대한 다중 반향은 양호하지만 중요하지는 않지만 읽기가 더 쉽습니다. (3) 동의하고, (4) 확실하지만 변수가 포함하는 것으로 시작하면 실패합니다. (5) 알겠습니다.
pLumo

@RoVo 나는 당신의 1)에 동의합니다. 4)의 경우, 변수는 pb가 사라지게하는 데 필요한만큼 복잡 할 수 있습니다 (예 : uniquetag="banaNa11F453355B28E1158D4E516A2D3EDF96B3450406...)
Olivier Dulac

1
확실하지는 않지만 나중에 보안 문제가 발생할 수 있습니다. 그런 다음 파일로 인쇄하기 전에 해당 문자열을 제거하고 싶을 수도 있습니다. ;-)
pLumo

2

출력 순서가 stdout이면 stderr ; 리디렉션 만있는 솔루션은 없습니다.
stderr은 임시 파일에 저장해야합니다

cmd 2>>file-err | tee -a file1 >>file2
cat file-err >> file1
rm file-err

기술:

하나의 출력 (stdout 또는 stderr와 같은 fd)을 파일 로 리디렉션하는 유일한 방법은 출력 을 재생하는 것입니다. 이 명령 tee은 파일 디스크립터 컨텐츠를 재생하는 올바른 도구입니다. 따라서 두 파일에 하나의 출력을 갖는 초기 아이디어는 다음을 사용하는 것입니다.

... |  tee file1 file2

이것은 티의 stdin을 두 파일 (1 & 2)로 재생하여 티의 출력을 여전히 사용하지 않습니다. 그러나 우리는 (use -a) 를 추가해야하고 사본 하나만 필요합니다. 이렇게하면 두 가지 문제가 모두 해결됩니다.

... | tee -a file1 >>file2

공급하려면 tee우리는 명령에서 직접 표준 에러 소비 할 필요가 표준 출력 (반복에 하나)와 함께. 한 가지 방법은 순서가 중요하지 않은 경우 (출력 순서는 생성 된대로 유지 될 것입니다 (아마도 먼저 출력되는 쪽이 먼저 저장 됨)). 어느 한 쪽:

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

옵션 2는 일부 쉘에서만 작동합니다. 옵션 3은 추가 서브 쉘 (느리게)을 사용하지만 파일 이름은 한 번만 사용하십시오.

하지만 표준 출력이 해야한다 먼저 우리는 마지막에 파일에 추가 할 저장 stderr에 필요 (중 위해 출력하는 생성) (최초의 솔루션이 게시).


1
또는 다음과 같은 메모리에 저장하십시오 sponge.(cmd | tee -a out >> out+err) 2>&1 | sponge >> out+err
Stéphane Chazelas

1

다양성을 위해 :

시스템 지원하는 경우 /dev/stderr, 다음

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

작동합니다. 의 표준 출력은 cmd 파이프 라인의 stdout 및 stderr 모두로 전송됩니다. cmd바이 패스 의 표준 오차 는tee 는 파이프 라인 하고 나옵니다.

그래서

  • 파이프 라인의 표준 출력은 cmd
  • 파이프 라인의 stderr cmd은의 혼합 된 stdout과 stderr입니다 .

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

(을 포함하여이 같은 거의 모든 방법과 마찬가지로 스테판의 대답 ), file1순서가 라인을 얻을 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.