bash 스크립트가 명령 행에서 파이핑없이 티를 사용하도록 강제


20

나는 많은 출력을 가진 bash 스크립트를 가지고 있으며, 새로운 출력을 만들지 않고 해당 스크립트를 변경하여 모든 출력을 파일로 복사하고 싶습니다.

script.sh 파일이 있습니다 .

#!/bin/bash
init
do_something_that_outputs_stuff_to_STDOUT
launch_applications_that_output_to_STDOUT
fini

매번 입력하지 않고도 script.log 파일에 STDOUT의 사본을 만들고 싶습니다 ./script.sh | tee script.log.

고마워, 톰


나는 이것을 이전에 말하지 않아서 유감이지만 스크립트가 길기 때문에 간단한 해결책을 찾고 있습니다. 추가 | 각 줄의 티가 너무 많습니다.
Tom

답변:


15

데니스의 단순한 단일 라이너를 작동시킬 수 없었기 때문에 훨씬 더 복잡한 방법이 있습니다. 나는 그의 첫 번째 시도합니다.

언급했듯이 exec를 사용하여 전체 스크립트에 대해 표준 오류 및 표준을 리디렉션 할 수 있습니다. 이렇게하면 :
exec > $LOGFILE 2>&1 모든 stderr 및 stdout을 $ LOGFILE로 출력합니다.

이제 이것을 로그 파일과 함께 콘솔에 표시하고 싶기 때문에 exec에 쓰고 tee에 읽을 명명 된 파이프를 사용해야합니다.
(Dennis의 단일 라이너는 기술적으로도 다른 방식으로도 수행합니다.) 파이프 자체는로 생성됩니다 mkfifo $PIPEFILE. 그런 다음 다음을 수행하십시오.

# 로그 파일에 티 쓰기를 시작하지만 명명 된 파이프에서 입력을 가져옵니다.
티 $ LOGFILE <$ PIPEFILE &

# 대기 명령에 대한 티의 프로세스 ID를 캡처합니다.
TEEPID = $!

# stderr과 stdout의 나머지 부분을 명명 된 파이프로 리디렉션합니다.
실행> $ PIPEFILE 2> & 1

echo "여기에서 명령하십시오"
echo "모든 표준이 나올 것입니다."
echo "표준 오류가 발생합니다"> & 2

# stderr 및 stdout 파일 디스크립터를 닫으십시오.
exec 1> &-2> &-

# 파이프의 다른 쪽 끝이 닫히고 티가 끝날 때까지 기다립니다.
$ TEEPID 대기

철저하게하려면 스크립트의 시작과 끝에서 명명 된 파이프 파일을 작성하고 파기 할 수 있습니다.

기록을 위해, 나는 임의의 사람의 매우 유익한 블로그 게시물에서 대부분을 수집했습니다 : ( Archived version )


cygwin에서는 작동하지 않는 것 같습니다. :-(
docwhat

이 게시물은 훌륭한 교육 업무를 수행합니다. 대단히 감사합니다.
Felipe Alvarez

27

이것을 스크립트 시작 부분에 추가하면됩니다.

exec > >(tee -ia script.log)

그러면 stdout으로 전송 된 모든 출력이 파일에 추가 script.log되어 이전 내용이 그대로 유지됩니다. 스크립트가 실행될 때마다 새로 시작하려면 rm script.log해당 exec명령 바로 앞에 추가 하거나 명령 -a에서 제거하십시오 tee.

-i옵션은 tee인터럽트 신호를 무시 tee하고보다 완전한 출력 세트를 포착 할 수 있습니다 .

이 줄을 추가하여 모든 오류를 (별도의 파일로) 포착하십시오.

exec 2> >(tee -ia scripterr.out)

여러 >기호 사이의 공백 이 중요합니다.


매우 흥미로운 해결책.
ℝaphink

2
이것은 내가 게시 한 모든 쓰레기와 비교할 때 정말 우아한 방법입니다. 그러나 그 두 줄로 스크립트를 만들면 중단되고 절대로 종료되지 않습니다.
Christopher Karel


RHEL5.3 설치의 일부로 GNU bash, 버전 3.2.25 (1). 공식 리포지토리의 최신 버전 인 것 같습니다.
Christopher Karel

방금 Bash 3.2.49 (23) -release의 cygwin에서 시도했지만 파일 설명자 오류가 발생했습니다. Ubuntu 9.10의 Bash 4.0.33 (1) 릴리스에서 작동하므로 Bash 4 일 수 있습니다.
추후 공지가있을 때까지 일시 중지되었습니다.

6

이것은 이전에 Dennis Williamson이 게시 한 답변의 결합 된 버전입니다. err & std를 script.log에 올바른 순서로 추가합니다.

이 줄을 스크립트의 시작 부분에 추가하십시오.

exec > >(tee -a script.log) 2>&1

>표지판 사이의 간격을 확인하십시오 . GNU bash, 버전 3.2.25 (1)-릴리스 (x86_64-redhat-linux-gnu)에서 작동합니다


5

다른 접근법이 다음과 같다고 생각합니다.

#!/bin/bash

# start grouping at the top
{ 
    # your script goes here
    do_something_that_outputs_stuff_to_STDOUT
    launch_applications_that_output_to_STDOUT

# and at the bottom, redirect everything from the grouped commands
} 2>&1 | tee script.log 

3

출력 사본을 원하면 다음과 같이 사용할 수 있습니다 tee.

  #!/bin/bash
  init
  do_something_that_outputs_stuff_to_STDOUT | tee script.log
  launch_applications_that_output_to_STDOUT | tee -a script.log
  fini

그러나 이것은 stdout 만 script.log에 기록합니다. stderr 및 stdout이 모두 리디렉션되도록하려면 다음을 사용하십시오.

  #!/bin/bash
  init
  do_something_that_outputs_stuff_to_STDOUT 2>&1 | tee script.log
  launch_applications_that_output_to_STDOUT 2>&1 | tee -a script.log
  fini

약간의 기능으로 조금 더 멋지게 만들 수도 있습니다.

  #!/bin/bash

  LOGFILE="script.log"
  # Wipe LOGFILE if you don't want to add to it at each run
  rm -f "$LOGFILE"

  function logcmd() {
        local cmd="$1" logfile=${LOGFILE:-script.log} # Use default value if unset earlier

        # Launch command, redirect stderr to stdout and append to $logfile
        eval '$cmd' 2>&1 | tee -a "$logfile"
  }

  init
  logcmd "do_something_that_outputs_stuff_to_STDOUT"
  logcmd "launch_applications_that_output_to_STDOUT"
  fini

좋은 대답입니다. 그가 정말로 stdout에 관심이 있다면, 나는 2>&1밖으로 나가서 티에 파이프 할 것입니다.
DaveParillo 2009

사실, Igor의 이전 답변이 그것을 리디렉션하기를 원했기 때문에 stderr 만 포함했으며 좋은 아이디어라고 생각했습니다.
ℝaphink

1

당신은 이것을 사용할 것입니다 :

script logfile.txt
your script or command here

그러면 로그에 모든 것이 출력되고 화면에 표시됩니다. FULL 출력을 원하면이 방법을 사용하십시오.

그리고 게으른 경우 스크립트를 재생할 수 있습니다.


script예를 들어 패키지 라는 점에 유의하십시오 . sudo apt-get install script데비안 풍향 배포판 에 설치하려면 script -ac 'command opts' ~/Documents/some_log.script다음과 같이 터미널 내 에서 추가 로 검토 할 수 있습니다 strings ~/Documents/some_log.script | more. 더 멋진 재생 /보기 방법 을 허용하기 위해 주입strings 하는 것들 중 일부를 미리 위생 ​​처리하는 간단한 방법이어야합니다 . 그렇지 않으면 대화 형도 유지 하기 때문에 @Phishy의 확실한 대답 입니다. script script
S0AndS0

0
#!/bin/bash
init
do_something_that_outputs_stuff_to_STDOUT > script.log 2>&1
launch_applications_that_output_to_STDOUT >> script.log 2>&1
fini

작동 방식에 대한 자세한 내용은 http://www.xaprb.com/blog/2006/06/06/what-does-devnull-21-mean/을 참조 하십시오.


1
Igor의 답변에서 두 번째 줄에 두 번째>를 추가하여 첫 번째 줄에 작성된 로그를 지우지 않습니다.
Doug Harris

1
그러나 사본을 원하므로를 사용해야 tee합니다.
ℝaphink

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