파이프를 사용하지 않고 표준 출력을 터미널 및 파일로 리디렉션하시겠습니까?

파이프를 사용하지 않고 표준 출력을 터미널 및 파일로 리디렉션하시겠습니까?

다음과 같은 코드가 있습니다.

#!/bin/bash

VAR=0

func() {
    VAR=$((VAR+1))
    echo 'Logging information.'
}

func 2>&1 | tee 'log.txt'

echo "Should be 1: ${VAR}"

호출되면 다음과 같은 일이 발생합니다.

:~$ ./script.sh
Should be 1: 0

제가 이해한 바로는 제가 사용하고 있는 파이프라인이 서브쉘을 생성하기 때문입니다. in에 대한 변경 사항은 VAR위쪽으로 전파되지 않으므로 출력에 반영되지 않습니다.

func내 경우에는 프로세스가 다소 길었고 출력이 실시간으로 이루어져야 했습니다. 따라서 파일에 쓴 다음 cat해당 파일을 읽는 것은 옵션이 아닙니다. 또한 가능하면 파일에 아무것도 쓰지 않고 변수로 다시 읽는 것을 피하고 싶습니다.

그렇다면 파이프에 대한 필요성을 충족시킬 수 있는 방법이 있습니까? 아니면 제가 아직 모르는데 도움이 될 수 있는 bash 트릭이 있습니까?

편집하다:

명명된 파이프를 사용해 보십시오.

#!/bin/bash

VAR=0

func() {
        VAR=$((VAR+1))
        echo 'Logging information.'
        sleep 5
}

mkfifo my_fifo

func >my_fifo 2>&1 &

tee 'log .txt' <my_fifo

echo "Should be 1: ${VAR}"

불행히도 결과는 동일합니다.

:~$ ./script.sh
Should be 1: 0

답변1

다음을 수행할 수 있습니다.

func > >(tee log.txt) 2>&1
wait

로깅 전용 파일 설명자를 지정할 수 있습니다.

exec 3> >(tee log.txt)
tee_pid=$!

func >&3 2>&1
...

그러나 tee백그라운드에서 실행되므로 모든 출력이 통과하지 않으면 출력 순서가 영향을 받을 수 있습니다.

답변2

TMP 파일을 사용할 수 있습니다

func >tmpfile 2>&1
tee 'log.txt' <tmpfile

또는 선입선출

mkfifo pipe_replacement
tee 'log.txt' <pipe_replacement &
func >pipe_replacement 2>&1

답변3

난 이걸 할거야...

#!/bin/sh -x
run() if ! ps -p "$run" >&2
      then n=0 run=$$ exec "$0" "$@" 2>&1 | {
         ! tee outfile ; }
      fi 2>/dev/null
run "$@" || exit

fn() { var=val$n; echo "$((n+=1)): $var"; }
fn 
sleep 5
fn
IN

먼저 다른 프로세스에 대한 파이프를 열었는지 확인합니다 tee. 그렇지 않은 경우 exec프로세스 자체에 들어갑니다. 그런 다음 모든 출력은 스크립트의 나머지 부분으로 파이프되고 그 사이에 설정된 모든 변수와 스크립트 종료가 유지됩니다. 실제로 이것이 처음부터 확인되는 방법입니다.

따라서 위의 인쇄를 실행하십시오.

+ run
+ run
+ fn
+ var=val0
+ echo 1: val0
1: val0
+ sleep 5
+ fn
+ var=val1
+ echo 2: val1
2: val1
+ exit

그런 다음 인쇄를 실행하십시오 cat outfile...

+ run
+ run
+ fn
+ var=val0
+ echo 1: val0
1: val0
+ sleep 5
+ fn
+ var=val1
+ echo 2: val1
2: val1
+ exit

성능이 더 높 더라도 sed대신 사용하는 것을 고려할 수도 있습니다 tee.tee전체 출력이 경우 sed여러 파일을 동시에 쓸 수 있으며 조건에 따라 수행할 수 있습니다.

예를 들어 다음과 같은 줄을 에코할 수 있습니다.

echo 'LOG-ONLY: some message here'

듣기 sed프로세스는 다음을 수행할 수 있습니다.

sed -n '/^LOG-ONLY:/!p;s///w ./my_log.txt'

... w부분을 제거한 후 파일에 줄을 쓰고 LOG_ONLY터미널에 인쇄하는 것을 방지합니다.

관련 정보