Program Tip

stdout을 변수로 캡처하지만 여전히 콘솔에 표시

programtip 2020. 11. 17. 20:59
반응형

stdout을 변수로 캡처하지만 여전히 콘솔에 표시


몇 가지 장기 실행 프로세스를 호출하는 bash 스크립트가 있습니다. 처리상의 이유로 이러한 호출의 출력을 변수로 캡처하고 싶습니다. 그러나 이들은 오래 실행되는 프로세스이기 때문에 rsync 호출의 출력 이 사실 이후가 아닌 실시간으로 콘솔에 표시되기를 바랍니다 .

이를 위해 나는 그것을하는 방법을 찾았 지만 텍스트를 / dev / stderr로 출력하는 것에 의존합니다. / dev / stderr로 출력하는 것이 좋은 방법이 아니라고 생각합니다.

VAR1=$(for i in {1..5}; do sleep 1; echo $i; done | tee /dev/stderr)

VAR2=$(rsync -r -t --out-format='%n%L' --delete -s /path/source1/ /path/target1 | tee /dev/stderr)

VAR3=$(rsync -r -t --out-format='%n%L' --delete -s /path/source2/ /path/target2 | tee /dev/stderr)

위의 예에서 rsync를 몇 번 호출하고 처리되는 파일 이름을보고 싶지만 나중에 파싱 할 것이기 때문에 결국에는 변수에 출력을 원합니다.

이를 수행하는 '더 깨끗한'방법이 있습니까?

차이가 나는 경우 Ubuntu 12.04, bash 4.2.24를 사용하고 있습니다.


쉘에서 & 1을 복제하고 (예제에서 5로) 서브 쉘에서 & 5를 사용하십시오 (부모 쉘의 표준 출력 (& 1)에 기록 할 수 있도록).

exec 5>&1
FF=$(echo aaa|tee >(cat - >&5))
echo $FF

서브 쉘의 에코로 인해 aaa를 두 번 인쇄하고 두 번째로 변수 값을 인쇄합니다.

코드에서 :

exec 5>&1
VAR1=$(for i in {1..5}; do sleep 1; echo $i; done | tee >(cat - >&5))
# use the value of VAR1

Op De Cirkel의 답변에는 올바른 아이디어가 있습니다. 훨씬 더 단순화 할 수 있습니다 (사용하지 cat않음).

exec 5>&1
FF=$(echo aaa|tee /dev/fd/5)
echo $FF

다음은 stderr및 명령의 종료 코드를 모두 캡처하는 예 입니다. 이것은 Russell Davis의 답변을 기반으로합니다.

exec 5>&1
FF=$(ls /taco/ 2>&1 |tee /dev/fd/5; exit ${PIPESTATUS[0]})
exit_code=$?
echo "$FF"
echo "Exit Code: $exit_code"

폴더 /taco/있으면 내용을 캡처합니다. 폴더가 없으면 오류 메시지가 캡처되고 종료 코드는 2가됩니다.

생략하면 2>&1stdout캡처됩니다.


세 개 이상의 파일 설명자를 사용할 수 있습니다. 여기에서 시도하십시오 :

http://tldp.org/LDP/abs/html/io-redirection.html

"열린 각 파일에는 파일 설명자가 할당됩니다. [2] stdin, stdout 및 stderr에 대한 파일 설명자는 각각 0, 1, 2입니다. 추가 파일을 열려면 설명자 3 ~ 9가 남아 있습니다. 이러한 추가 파일 설명자 중 하나를 stdin, stdout 또는 stderr에 임시 중복 링크로 지정하십시오. "

요점은이 결과를 얻기 위해 스크립트를 더 복잡하게 만드는 것이 가치가 있는지 여부입니다. 사실 그것은 당신이하는 방식에있어서 정말 잘못된 것이 아닙니다.


"콘솔"이 현재 TTY를 의미하는 경우

variable=$(command with options | tee /dev/tty)

이것을 사용하려는 사람들은 TTY (cron 작업 등)가 없을 때 예상치 못한 위치에 출력이 나올 때 놀라는 경우가 있기 때문에 약간 모호한 방법입니다.


을 사용 /dev/tty하거나 다른 답변에서 제안한 추가 파일 설명자를 사용하는 대신 뒤집어서 임시 파일을 사용할 수도 있습니다. 이것은 분명 읽기 쉽고 특정 상황에서 더 쉽게 이식 할 수 있습니다.

tmpFile=$(mktemp)  # mak-a de temp
rsync /a /b | tee $tmpFile # sync my b*tch up
if grep "U F'd up" $tmpFile; then
  rm -rf / #Seppuku
fi

참고 URL : https://stackoverflow.com/questions/12451278/capture-stdout-to-a-variable-but-still-display-it-in-the-console

반응형