development

파이프로“티”를 사용하는 동안 파일에 stderr를 쓰려면 어떻게해야합니까?

big-blog 2020. 2. 12. 23:41
반응형

파이프로“티”를 사용하는 동안 파일에 stderr를 쓰려면 어떻게해야합니까?


내가 사용하는 방법을 알고 tee출력 (작성 STDOUT중) aaa.sh에을 bbb.out여전히 단말기에 표시하는 동안 :

./aaa.sh | tee bbb.out

STDERR라는 파일에 ccc.out여전히 표시하면서 어떻게 파일을 작성 합니까?


터미널에 STDERR 및 STDOUT이 계속 표시되기를 원한다고 가정합니다. 조쉬 켈리 (Josh Kelley)의 답변을 얻을 수는 있지만 tail로그 파일을 매우 해킹하고 어리석게 출력하는 백그라운드를 유지합니다 . exra FD를 어떻게 유지하고 나중에 죽여서 정리해야하는지 기술적으로 기술적으로해야합니다 trap '...' EXIT.

이를 수행하는 더 좋은 방법이 있으며 이미 발견했습니다 tee..

stdout에 사용하는 대신 stdout에 대한 티와 stderr에 대한 티를 사용하십시오. 당신은 이것을 어떻게 성취 할 것입니까? 프로세스 대체 및 파일 리디렉션 :

command > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)

그것을 나누고 설명합시다.

> >(..)

>(...)(프로세스 대체) FIFO를 작성하고 tee청취하십시오. 그런 다음 >(파일 리디렉션)을 사용 하여 STDOUT을 command처음 tee듣고 있는 FIFO 로 리디렉션합니다 .

두 번째도 마찬가지입니다.

2> >(tee -a stderr.log >&2)

프로세스 대체를 다시 사용 tee하여 STDIN에서 읽고 프로세스를 덤프 하는 프로세스 를 만듭니다 stderr.log. tee입력을 STDOUT에 다시 출력하지만 입력이 STDERR이므로 tee의 STDOUT을 STDERR로 다시 리디렉션하려고 합니다. 그런 다음 파일 리디렉션을 사용하여 command의 STDERR을 FIFO의 입력 ( teeSTDIN) 으로 리디렉션 합니다.

http://mywiki.wooledge.org/BashGuide/InputAndOutput을 참조하십시오 .

프로세스 대체는 (POSIX 또는 Bourne) bash과 달리 쉘로 선택하는 보너스로 얻는 정말 멋진 것들 중 하나입니다 sh.


에서 sh수동으로 작업을 수행해야합니다.

out="${TMPDIR:-/tmp}/out.$$" err="${TMPDIR:-/tmp}/err.$$"
mkfifo "$out" "$err"
trap 'rm "$out" "$err"' EXIT
tee -a stdout.log < "$out" &
tee -a stderr.log < "$err" >&2 &
command >"$out" 2>"$err"

왜 간단하지 않습니까?

./aaa.sh 2>&1 | tee -a log

이것은 단순히 리디렉션 stderr하기 stdout, 티 에코 그래서 모두가 로그인 화면에 할 수 있습니다. 다른 솔루션 중 일부가 실제로 복잡해 보이므로 뭔가 빠졌을 수 있습니다.

참고 : bash 버전 4부터 다음에|& 대한 약어로 사용할 수 있습니다 2>&1 |.

./aaa.sh |& tee -a log

이것은 구글을 ​​통해 이것을 찾는 사람들에게 유용 할 수 있습니다. 시도하려는 예제의 주석을 해제하십시오. 물론 출력 파일 이름을 자유롭게 바꾸십시오.

#!/bin/bash

STATUSFILE=x.out
LOGFILE=x.log

### All output to screen
### Do nothing, this is the default


### All Output to one file, nothing to the screen
#exec > ${LOGFILE} 2>&1


### All output to one file and all output to the screen
#exec > >(tee ${LOGFILE}) 2>&1


### All output to one file, STDOUT to the screen
#exec > >(tee -a ${LOGFILE}) 2> >(tee -a ${LOGFILE} >/dev/null)


### All output to one file, STDERR to the screen
### Note you need both of these lines for this to work
#exec 3>&1
#exec > >(tee -a ${LOGFILE} >/dev/null) 2> >(tee -a ${LOGFILE} >&3)


### STDOUT to STATUSFILE, stderr to LOGFILE, nothing to the screen
#exec > ${STATUSFILE} 2>${LOGFILE}


### STDOUT to STATUSFILE, stderr to LOGFILE and all output to the screen
#exec > >(tee ${STATUSFILE}) 2> >(tee ${LOGFILE} >&2)


### STDOUT to STATUSFILE and screen, STDERR to LOGFILE
#exec > >(tee ${STATUSFILE}) 2>${LOGFILE}


### STDOUT to STATUSFILE, STDERR to LOGFILE and screen
#exec > ${STATUSFILE} 2> >(tee ${LOGFILE} >&2)


echo "This is a test"
ls -l sdgshgswogswghthb_this_file_will_not_exist_so_we_get_output_to_stderr_aronkjegralhfaff
ls -l ${0}

stderr을 파일로 리디렉션하려면 stdout을 화면에 표시하고 stdout을 파일에 저장하십시오.

./aaa.sh 2> ccc.out | 티 ./bbb.out

편집 : stderr 및 stdout을 화면에 표시하고 파일에 모두 저장하려면 bash의 I / O 리디렉션을 사용할 수 있습니다 .

#!/bin/bash

# Create a new file descriptor 4, pointed at the file
# which will receive stderr.
exec 4<>ccc.out

# Also print the contents of this file to screen.
tail -f ccc.out &

# Run the command; tee stdout as normal, and send stderr
# to our file descriptor 4.
./aaa.sh 2>&4 | tee bbb.out

# Clean up: Close file descriptor 4 and kill tail -f.
exec 4>&-
kill %1

즉, stdout을 한 필터 ( tee bbb.out) 에 파이프 하고 stderr를 다른 필터 ( tee ccc.out) 에 파이프하려고합니다 . stdout 이외의 다른 것을 다른 명령으로 파이프하는 표준 방법은 없지만 파일 설명자를 저글링하여 해결할 수 있습니다.

{ { ./aaa.sh | tee bbb.out; } 2>&1 1>&3 | tee ccc.out; } 3>&1 1>&2

표준 오류 스트림을 잡는 방법 (stderr) 도 참조하십시오 . 그리고 언제 추가 파일 디스크립터를 사용한다?

bash (및 ksh 및 zsh)에서는 대시와 같은 다른 POSIX 셸에서는 프로세스 대체를 사용할 수 있습니다 .

./aaa.sh > >(tee bbb.out) 2> >(tee ccc.out)

bash ./aaa.sh에서 tee명령이 여전히 실행 되더라도이 명령은 완료 되 자마자 리턴합니다 (ksh 및 zsh는 서브 프로세스를 기다립니다). 다음과 같은 작업을 수행하면 문제가 될 수 있습니다 ./aaa.sh > >(tee bbb.out) 2> >(tee ccc.out); process_logs bbb.out ccc.out. 이 경우 대신 파일 디스크립터 저글링 또는 ksh / zsh를 사용하십시오.


bash를 사용하는 경우 :

# Redirect standard out and standard error separately
% cmd >stdout-redirect 2>stderr-redirect

# Redirect standard error and out together
% cmd >stdout-redirect 2>&1

# Merge standard error with standard out and pipe
% cmd 2>&1 |cmd2

신용 (내 머리 위에서 대답하지 않음)은 여기에 있습니다 : http://www.cygwin.com/ml/cygwin/2003-06/msg00772.html


필자의 경우 stdout과 stderr을 파일로 리디렉션하는 동안 스크립트가 명령을 실행 중이었습니다.

cmd > log 2>&1

오류가 발생했을 때 오류 메시지를 기반으로 몇 가지 조치를 취하도록 업데이트해야했습니다. 물론 dup을 제거하고 2>&1스크립트에서 stderr을 캡처 할 수는 있지만 오류 메시지는 참조를 위해 로그 파일로 이동하지 않습니다. @lhunath에서 받아 들인 대답은 똑같이해야하지만 리디렉션 stdout하고 stderr다른 파일로 리디렉션 합니다. 원하는 것이 아니지만 필요한 정확한 솔루션을 찾는 데 도움이되었습니다.

(cmd 2> >(tee /dev/stderr)) > log

위로, 로그는 모두의 사본을해야합니다 stdout그리고 stderr내가 캡처 할 수 있습니다 stderr에 대해 걱정할 필요없이 내 스크립트 stdout.


다음은 프로세스 대체가 불가능한 KornShell (ksh)에서 작동합니다.

# create a combined(stdin and stdout) collector
exec 3 <> combined.log

# stream stderr instead of stdout to tee, while draining all stdout to the collector
./aaa.sh 2>&1 1>&3 | tee -a stderr.log 1>&3

# cleanup collector
exec 3>&-

여기서의 실제 트릭 2>&1 1>&3은 우리의 경우 stderrto stdout를 리디렉션하고 stdoutto descriptor를 리디렉션하는 순서입니다 3. 이 시점에서 stderrstdout아직 결합되지 않았습니다.

실제로 stderr(as stdin)는 설명자 3에 tee로그인 stderr.log하고 설명자 3으로 리디렉션됩니다.

그리고 기술자 3combined.log항상 그것을 기록 하고 있습니다. 따라서 와를 combined.log모두 포함합니다 .stdoutstderr

참고 URL : https://stackoverflow.com/questions/692000/how-do-i-write-stderr-to-a-file-while-using-tee-with-a-pipe



반응형