다음과 같은 코드가 있습니다.
#!/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
터미널에 인쇄하는 것을 방지합니다.