터미널에서 입력을 읽는 스크립트입니다. stdout 리디렉션을 사용하여 스크립트를 호출하는 경우 tty 및 stdout으로 인쇄하도록 스크립트에 어떻게 지시합니까?

터미널에서 입력을 읽는 스크립트입니다. stdout 리디렉션을 사용하여 스크립트를 호출하는 경우 tty 및 stdout으로 인쇄하도록 스크립트에 어떻게 지시합니까?

터미널에 사용자의 입력이 필요한 스크립트가 있으므로 stdout을 파일로 리디렉션하여 스크립트를 호출하면 사용자에게 프롬프트에 대한 컨텍스트가 없습니다. 그래서 표준 출력을 두 사이트 모두에 복사하고 싶습니다.

스크립트는 미적분학을 출력하므로 stdout 리디렉션을 허용하는 것이 여전히 의미가 있습니다.

그러나 stdin이 제공되면(yes 명령이나 cron과 같은 비대화형 컨텍스트와 유사) tty에 있을 필요 없이 출력을 허용하는 것이 합리적입니다.

그래서 다음과 같은 논리를 수행하고 싶습니다.

If (test -t 0 && ! test -t 1);
  // Tell stdout to print everything  to tty as well

가능합니까? 아니면 단순히 부적절합니까?

답변1

프롬프트 문자열에 관심이 있다면 일반적으로 stderr로 이동해야 합니다. 이는 대부분의 유틸리티 회사가 팁을 발행할 때 수행하는 작업입니다. 예를 들어 read 'var?prompt또는 ksh/zsh/yash read -p prompt var또는 를 참조하세요 bash.

이렇게 하면 일반 출력과 분리되어 안전하게 리디렉션할 수 있습니다.

stdin이 tty에 있지만 stdout은 그렇지 않은 경우 요청한 작업을 계속 수행하고 제어 tty에 출력을 보내려면 ksh93, zsh 또는 bash를 포함한 일부 쉘에서 다음을 수행할 수 있습니다.

if [[ -t 0 && ! -t 1 ]]; then
  exec > >(tee /dev/tty)
fi

그러나 tee백그라운드에서 실행되기 때문에 터미널에 대한 출력이 잘못된 시간에 나타나는 것을 발견할 수 있습니다. 예를 들어:

$ zsh -c 'exec > >(tee /dev/tty); print before; read "var?Prompt: "; print -r "after: $var"' > /dev/null
Prompt: before
what?
after: what?

beforetty에 도달 했습니다뒤쪽에 read프롬프트가 발행되었습니다.

따라서 전역적으로 이러한 리디렉션을 수행하려면 모든 명령에 대해 수행해야 합니다. 또는 적어도 프롬프트를 발행하거나 stderr 또는 터미널에 자체적으로 쓰는 명령 사이의 모든 명령 그룹에 대해 수행해야 합니다. 또는 stdout/stderr도 각 명령에 대해 이상한 순서로 나타날 수 있습니다. .

#! /bin/zsh -
if [[ -t 0 && ! -t 1 ]]; then
  alias -g '{#}=>&1 > /dev/tty'
else
  alias -g '{#}='
fi
print before {#}
read 'var?prompt: '
print -r after: $var {#}

tee(fd가 여러 번 리디렉션되는 경우 여기서는 zsh의 내장 도구가 사용됩니다.)

관련 정보