쉘 스크립트 내에서 화면과 파일 모두에 텍스트를 출력하는 방법은 무엇입니까?


49

현재 메시지를 다음과 같이 로그 파일에 기록하는 쉘 스크립트가 있습니다.

log_file="/some/dir/log_file.log"
echo "some text" >> $log_file
do_some_command
echo "more text" >> $log_file
do_other_command

이 스크립트를 실행할 때 화면에 출력이 없으며 퍼티를 통해 서버에 연결하기 때문에 다른 연결을 열고 "tail -f log_file_path.log"를 실행해야합니다. 실행을 종료 할 수 없기 때문입니다. 스크립트와 실시간으로 출력을보고 싶습니다.

분명히, 내가 원하는 것은 문자 메시지가 화면과 파일로 인쇄되는 것이지만 두 줄이 아닌 한 줄로하고 싶습니다. 하나는 파일로 리디렉션되지 않습니다.

이것을 달성하는 방법?

답변:


71

이것은 작동합니다 :

command | tee -a "$log_file"

tee입력을 파일에 저장하고 ( -a덮어 쓰기보다는 추가하는 데 사용 ) 입력을 표준 출력에도 복사합니다.


8

here-doc 및을 사용할 수 있습니다. 효율적이고 POSIX 친화적 인 일반 수집기 모델을 제공합니다.

. 8<<-\IOHERE /proc/self/fd/8

command
 
fn() { declaration ; } <<WHATEVER
# though a nested heredoc might be finicky
# about stdin depending on shell
WHATEVER
cat -u ./stdout | ./works.as >> expect.ed
IOHERE

heredoc을 열면 IOHERE 입력 토큰으로 쉘에 신호를 보내 리미터 토큰의 다른 끝에 도달 할 때까지 지정한 파일 설명 자로 입력을 재지 정해야합니다. 나는 둘러 보았지만 heredoc 연산자와 함께 위에서 보았 듯이 리디렉션 fd 번호 사용에 대한 많은 예를 보지 못했지만 사용법은 POSIX 기본 쉘 명령 지침에 명확하게 지정되어 있습니다. 대부분의 사람들은 stdin을 가리키고 쏘지 만, 이런 방식으로 소싱 스크립틀릿은 stdin을 자유롭게하고 구성 앱이 차단 된 I / O 경로에 대해 불평하는 것을 막을 수 있습니다.

heredoc의 내용은 지정한 파일 디스크립터로 스트리밍되며,이 파일 디스크립터는 쉘 코드로 해석되어에 의해 실행됩니다. 에 대한 특정 경로를 지정하지 않고 내장되어 있습니다. . / proc / self 경로에 문제가 있으면 / dev / fd / n 또는 / proc / $$를 시도하십시오. 이 같은 방법은 파이프에서 작동합니다.

cat ./*.sh | . /dev/stdin

아마도 보이는 것처럼 적어도 현명하지 않습니다. 물론 sh로도 똑같이 할 수 있지만.의 목적은 현재 쉘 환경에서 실행하는 것입니다.이 쉘은 아마도 원하는 것입니다. 쉘에 따라 heredoc보다 훨씬 더 가능성이 높습니다. 표준 익명 파이프로.

어쨌든, 아마 당신이 알아 차렸 듯이, 나는 여전히 당신의 질문에 대답하지 않았습니다. 그러나 당신이 그것에 대해 생각하면 heredoc이 모든 코드를. 's로 스트리밍하는 것과 같은 방식으로 단일의 간단한 아웃 포인트를 제공합니다.

. 5<<EOIN /dev/fd/5 |\ 
    tee -a ./log.file | cat -u >$(tty)
script
 
more script
EOIN

따라서 heredoc에서 실행 된 코드의 모든 터미널 stdout은에서 파이프 아웃됩니다. 당연히 단일 파이프에서 쉽게 분리 할 수 ​​있습니다. 현재 stdout 방향에 대해 명확하지 않기 때문에 버퍼링되지 않은 고양이 호출을 포함했지만 아마도 중복되어있을 것입니다 (거의 확실하게 작성되었습니다). 파이프 라인은 아마도 티에서 끝날 수 있습니다.

두 번째 예에서 누락 된 백 슬래시 따옴표에 의문을 가질 수도 있습니다. 이 부분은 뛰어 들기 전에 이해하는 것이 중요하며 사용 방법에 대한 몇 가지 아이디어를 줄 수 있습니다. 인용 된 heredoc 리미터 (지금까지 우리는 IOHERE와 EOIN을 사용했으며 처음으로 백 슬래시로 인용했지만 '단일'또는 '더블'따옴표는 동일한 목적을 제공하지만)는 쉘이 매개 변수 확장을 수행하지 못하게합니다. 인용되지 않은 리미터는 내용을 확장 할 수 있도록 남겨 둡니다. heredoc이있을 때의 결과. 급격한 공급 :

. 3<<HD ${fdpath}/3
: \${vars=$(printf '${var%s=$((%s*2))},' `seq 1 100`)} 
HD
echo $vars
> 4,8,12 
echo $var1 $var51
> 4 104

heredoc 리미터를 인용하지 않았기 때문에 쉘은 내용을 읽을 때와 결과 파일 설명자를 제공하기 전에 내용을 확장했습니다. 실행하다. 이것은 본질적으로 명령이 두 번 구문 분석되었습니다-어쨌든 확장 가능 명령. 백 슬래시는 $ vars 매개 변수 확장을 인용했기 때문에 쉘은 첫 번째 패스에서 선언을 무시하고 백 슬래시 만 제거하므로 printf 확장 된 내용 전체가 null로 평가 될 수 있습니다. 두 번째 패스에서 스크립트를 소싱했습니다.

이 기능은 기본적으로 위험한 eval shell 내장이 제공 할 수있는 것입니다. 비록 인용이 eval보다 여기 문서에서 다루기가 훨씬 쉽고, 마찬가지로 위험 할 수도 있습니다. 신중하게 계획하지 않는 한 습관적으로 "EOF"제한기를 인용하는 것이 가장 좋습니다. 그냥 말하면

편집 : Eh, 나는 이것을 되돌아보고 약간 너무 스트레칭이라고 생각합니다. 여러 출력을 하나의 파이프에 연결하는 것이 가장 간단한 방법이라면 다음을 사용하는 것입니다.

{ or ( command ) list ; } | tee -a ea.sy >>pea.sy

curles는 현재 쉘에서 내용을 실행하려고 시도하지만 parens는 자동으로 소멸됩니다. 그래도 누구나 내 의견으로는. heredoc 솔루션은 특히 셸이 실제로 어떻게 작동하는지 이해하려는 경우 훨씬 더 유용한 정보입니다.

즐기세요!


3

설치 로그를 작성하기 위해 설치 스크립트를 수정하는 동안이 답변을 찾았습니다.

내 스크립트는 이미 다음과 같은 에코 문으로 가득합니다.

echo "Found OLD run script $oldrunscriptname"
echo "Please run OLD tmunsetup script first!"

그리고 나는 tee 문 (또는 기존 스크립트를 티로 호출하는 다른 스크립트)을 실행하고 싶지 않기 때문에 이것을 썼습니다.

#!/bin/bash
# A Shell subroutine to echo to screen and a log file

LOGFILE="junklog"

echolog()
(
echo $1
echo $1 >> $LOGFILE
)


echo "Going"
echolog "tojunk"

# eof

이제 원래 스크립트에서 'echo'를 'echolog'로 변경하여 로그 파일의 출력을 원할 수 있습니다.

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