나는 일부 사용자 입력(예: 비밀번호 요청)을 읽기 위해 bash 스크립트를 작성 중이며 결과를 캡처하여 표준 출력을 통해 전달하려고 합니다. (저는 최신 소프트웨어를 사용하여 GNU/Linux 환경에서 작업하고 있습니다.)
다음은 문제를 재현하는 간단한 버전의 스크립트입니다.
....
# read_input.sh
#
# Issue B : redirection of "3>&1" here causes stty error when
# this script is executed via a command subsitution context subshell
exec 3>&1 </dev/tty >/dev/tty
tty_settings=`stty -g`
# Issue A : uncommented version doesn't restore tty properly.
#trap 'stty "$tty_settings";' EXIT
#trap 'echo "...interrupting"; exit 1' INT ABRT HUP QUIT TERM
trap 'echo "...interrupting"; stty "$tty_settings"; exit 1' INT ABRT HUP QUIT TERM
stty -echo
echo "Enter input: "
input=""
while IFS= read -r -n1 char; do
# nb: stripped out proper char handling code here,
# (except return), for simplicity
if [[ $char = "" ]]; then
break
fi
input+=$char
echo -n "*"
done
echo ""
stty "$tty_settings"
#trap - EXIT INT ABRT HUP QUIT TERM
trap - INT ABRT HUP QUIT TERM
echo "$input" >&3
목적은 결과 입력을 fd 3(호출 시 이 스크립트의 stdout이 파이프에 연결된 경우)에 기록하는 동시에 상호 작용 중에 tty를 유지하는 것입니다. 그런 다음 stty를 사용하여 tty를 수정하여 에코 등을 제어하고 트랩 처리를 통해 모든 수정 사항을 되돌립니다.
두 가지 문제에 직면했습니다.
질문 A
제어 터미널로 돌아온 후에는 에코가 억제됩니다. 주석 처리되지 않은 활성 한 줄 핸들러 케이스 대신 두 줄 트랩 핸들러 케이스(주석 처리됨)를 사용해야 합니다.
한 줄의 경우 - INT라고 말하면 tty를 복원한 다음 핸들러를 통해 종료를 호출합니다. EXIT 자체를 캡처하는 것이 아닙니다. 왜 이 작업을 수행해야 합니까?
질문 B
이는 서브셸 컨텍스트에서 exec의 "3>&1" 리디렉션과 관련이 있습니다.
어떤 이유에서인지 서브셸에서 이 스크립트("read_input.sh")를 실행하고 명령 대체를 통해 다른 스크립트에서 출력을 가져오고 싶다고 가정해 보겠습니다.
....
# read_input_caller.sh
input=$(sh read_input.sh)
echo "$input"
호출 스크립트를 중단할 때 트랩 핸들러의 stty 호출이 다음(^C로 표시됨)을 불평하는 것을 발견했습니다.
stty: '표준 입력': 입력/출력 오류
이 오류 메시지는 exec 라인의 "3>&1" 리디렉션으로 인해 발생합니다. "3>&1" 없이 exec 라인을 호출하면 stty 오류가 없습니다(그러나 입력을 stdout에 전달하는 데는 그다지 유용하지 않습니다). 왜 이런 일이 발생하는지 알 수 없나요?
호출 스크립트에서 다른 하위 쉘은 다음과 같이 호출합니다.
....
sh read_input.sh | cat
이 오류는 생성되지 않습니다.
흥미롭게도 문제 B가 발생하면 문제 A의 문제 캡처/복구에도 불구하고 터미널을 제어하는 tty가 올바르게 복원되는 것으로 보입니다.